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

Compare commits

...

79 Commits

Author SHA1 Message Date
dudaodong
91bc1a512c test: update TestZipFolder 2023-08-22 10:49:46 +08:00
dudaodong
8753255026 doc: update link in readme 2023-08-22 10:43:52 +08:00
dudaodong
9cf1f13fec doc: update link in readme 2023-08-22 10:39:37 +08:00
dudaodong
5d78bae4bb doc: update link in readme 2023-08-22 10:34:16 +08:00
dudaodong
27777eecc0 doc: update copyonwritelist doc 2023-08-22 10:26:39 +08:00
dudaodong
1a7e0e8792 doc: add copyonwritelist 2023-08-22 10:25:21 +08:00
dudaodong
02b7aa8f33 update version 2023-08-22 10:18:21 +08:00
dudaodong
f188d3d08f doc: add doc for InDelta 2023-08-21 11:05:11 +08:00
dudaodong
0c924b859e Merge branch 'main' into v2 2023-08-21 11:00:23 +08:00
warpmatrix
c5a5a07462 feat: InDelta (#127) 2023-08-15 09:53:16 +08:00
dudaodong
1ff5dd6df0 Merge branch 'main' into v2 2023-08-03 15:06:15 +08:00
Faucherwind
b5f86a488c feat: CopyOnWriteList adds more functions such as ForEach, Sort... (#126)
* feat: CopyOnWriteList adds more functions such as ForEach, Sort

* feat: CopyOnWriteList adds more functions such as ForEach, Sort
2023-08-03 15:05:30 +08:00
dudaodong
1390b7a964 fix: fix bug of Zip 2023-08-03 10:45:48 +08:00
dudaodong
c3e28a9fc0 fix: fix bug of Zip 2023-08-02 20:17:55 +08:00
dudaodong
e924429d6e fix: fix test case TestConcurrentMap_GetAndDelete 2023-08-02 11:33:27 +08:00
dudaodong
7079b1f704 format doc 2023-08-02 11:29:51 +08:00
Faucherwind
40cad365c0 feat: add CopyOnWriteList. A thread-safe list. (#125)
* fix: use loop to get value . On Get() and Contains()

* fix: Use reflect. DeepEqual() determines whether the keys are equal

* feat: add CopyOnWriteList. A thread-safe list.

* fix: fix failed unit test

* feat: add Equal() in CopyOnWriteList.

fix: update some function`s  names

* doc: add copyonwritelist.md and copyonwritelist_zh-CN.md
2023-08-02 11:10:10 +08:00
Faucherwind
6386ab908d fix: use loop to get value . On Get() and Contains() (#124)
* fix: use loop to get value . On Get() and Contains()

* fix: Use reflect. DeepEqual() determines whether the keys are equal
2023-08-01 11:14:45 +08:00
dudaodong
bb563724c7 doc: add go playground demo 2023-08-01 11:01:57 +08:00
dudaodong
72924d4486 release v2.2.4 2023-08-01 09:58:53 +08:00
dudaodong
231f8b04b4 doc: add new function doc for v2.2.4 2023-07-30 13:22:32 +08:00
dudaodong
daa932fee3 update: make IsWeekend deprecated 2023-07-30 12:47:00 +08:00
dudaodong
1b0691f1d5 Merge branch 'main' into v2 2023-07-30 12:41:03 +08:00
CyJaySong
0b6a00bd99 IsWeekend func Deprecated (#123)
* expand BeginOfWeek、EndOfWeek

* IsWeekend func Deprecated
2023-07-30 12:39:26 +08:00
dudaodong
4ab98664bb refactor: rename file name 2023-07-28 17:55:36 +08:00
dudaodong
31eb5f4d1f feat: add HmacMd5WithBase64 2023-07-28 17:53:46 +08:00
dudaodong
0ae5d17a06 doc: add doc for CurrentMap 2023-07-27 15:08:55 +08:00
dudaodong
4558d7a3c2 test: add test for currentmap 2023-07-27 11:54:52 +08:00
dudaodong
4715301240 doc: update doc for cryptor package 2023-07-27 11:20:06 +08:00
dudaodong
1c58ee23f1 feat: add Timestamp,TimestampMilli,TimestampMicro, TimestampNano 2023-07-26 17:28:15 +08:00
dudaodong
2a303d5e4b doc: update format 2023-07-26 15:28:20 +08:00
dudaodong
326e7881a6 feat: add NowDateOrTime 2023-07-26 15:03:59 +08:00
dudaodong
31e8b12674 feat: add timezone support for FormatTimeToStr and FormatStrToTime 2023-07-26 14:40:12 +08:00
dudaodong
a0431d9435 fix: fix TestConcurrentMap_Delete test failed 2023-07-25 10:21:11 +08:00
dudaodong
0456b65cc7 test: add example for cryptor package new functions 2023-07-25 10:18:54 +08:00
dudaodong
989b4dd791 test: add test for cryptor package new functions 2023-07-25 10:06:25 +08:00
dudaodong
a76b02fbba Merge branch 'main' into v2 2023-07-24 17:28:41 +08:00
hoslo
2d7747738a feat: add base cryptor method (#119)
Co-authored-by: shuai_yang <shuai_yang@intsig.net>
2023-07-24 17:24:17 +08:00
dudaodong
fe0cb04137 feat: add ConcurrentMap 2023-07-24 17:10:45 +08:00
dudaodong
fe0264f628 refactor: clean code 2023-07-24 15:42:36 +08:00
dudaodong
65396cee32 Merge branch 'main' into v2 2023-07-23 15:43:35 +08:00
Ta
544702b460 fix: remove unused message in pointer.md (#117) 2023-07-23 15:42:54 +08:00
dudaodong
d8936cdcb5 doc: add doc for pointer 2023-07-23 13:26:07 +08:00
dudaodong
d4b97d6b20 Merge branch 'main' into v2 2023-07-23 13:13:56 +08:00
Ta
5caa14c838 feat: add UnwarpOr and UnwarpOrDefault to pointer pkg (#116) 2023-07-23 13:09:50 +08:00
dudaodong
0d0848ac67 refactor: use for loop than for range 2023-07-10 10:56:53 +08:00
dudaodong
d5334f892f feat: add Join 2023-07-10 10:51:43 +08:00
dudaodong
36ef5b3bd3 doc: add doc for HasKey 2023-07-10 10:39:55 +08:00
dudaodong
6f48b00c88 feat: add HasKey 2023-07-10 10:33:04 +08:00
dudaodong
7b744c299e fix: fix bug of CreateDir 2023-07-10 10:13:23 +08:00
dudaodong
154ec56780 doc: add go playground demo 2023-07-04 16:31:13 +08:00
dudaodong
584aabdf62 release v2.2.3 2023-07-03 14:09:04 +08:00
dudaodong
1b754a6264 doc: update link in readme 2023-07-03 11:57:50 +08:00
dudaodong
06a558d797 doc: update link in readme 2023-07-03 11:21:49 +08:00
dudaodong
423779d3ff doc: update link in readme 2023-07-03 11:14:55 +08:00
dudaodong
78c17a9e7b doc: update link in readme 2023-07-03 10:52:26 +08:00
dudaodong
529b9317d0 doc: update link in readme 2023-07-03 10:48:04 +08:00
dudaodong
dc838f645b doc: update link in readme 2023-07-03 10:43:05 +08:00
dudaodong
7f559c4940 doc: update link in readme 2023-07-03 10:42:22 +08:00
dudaodong
acb08dfd90 doc: update link in readme 2023-07-03 10:40:50 +08:00
dudaodong
ffe46fd06d update readme file 2023-07-02 22:31:17 +08:00
dudaodong
b419e46b9b doc: add package index 2023-07-02 22:12:47 +08:00
dudaodong
8fbcdfd515 doc: add pointer and tuple package to readme file 2023-07-02 21:06:10 +08:00
dudaodong
f03f48210c doc: update system package 2023-06-30 15:12:18 +08:00
dudaodong
742944e2f0 doc: add doc for tuple package 2023-06-30 15:11:26 +08:00
dudaodong
c0b491ad78 doc: add example for tuple package 2023-06-30 11:20:46 +08:00
dudaodong
e9abae2a92 doc: add doc for pointer package 2023-06-30 10:31:22 +08:00
dudaodong
8229de2f10 test: add parallel running for all unit test functions 2023-06-30 10:18:45 +08:00
dudaodong
ab364744b6 test: add parallel running for all unit test functions 2023-06-29 14:49:28 +08:00
dudaodong
17ff84fa1f test: add test for Tuple Zip and Unzip 2023-06-29 11:34:43 +08:00
dudaodong
bf50baa07d feat: add GetTodayStartTime and GetTodayEndTime 2023-06-29 11:03:28 +08:00
dudaodong
7d56da8108 feat: add Md5Byte 2023-06-29 10:33:29 +08:00
dudaodong
16c2df711b feat: add unzip for tuple 2023-06-28 20:06:02 +08:00
dudaodong
015f8c3f5c feat: add zip 2023-06-28 19:41:46 +08:00
dudaodong
ba25701d89 feat: add zip 2023-06-28 17:52:12 +08:00
dudaodong
a0cb4bb266 doc: add example for tuple package 2023-06-28 16:25:43 +08:00
dudaodong
d6ba7497f9 feat: add Tuple package 2023-06-28 15:58:41 +08:00
dudaodong
7da931e0a0 feat: add Abs 2023-06-27 10:24:35 +08:00
dudaodong
8f49078eb3 doc: add go playground demo 2023-06-20 14:04:18 +08:00
102 changed files with 10632 additions and 312 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ fileutil/*.txt
fileutil/*.zip
fileutil/*.link
fileutil/unzip/*
fileutil/tempdir/*
slice/testdata/*
cryptor/*.pem
test

317
README.md
View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.2.5-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -24,7 +24,7 @@ English | [简体中文](./README_zh-CN.md)
## Feature
- 👏 Comprehensive, efficient and reusable.
- 💪 500+ go util functions, support string, slice, datetime, net, crypt...
- 💪 600+ go util functions, support string, slice, datetime, net, crypt...
- 💅 Only depends on two kinds of libraries: go standard library and golang.org/x.
- 🌍 Unit test for every exported function.
@@ -38,7 +38,7 @@ English | [简体中文](./README_zh-CN.md)
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. The latest of v1.x.x is v1.4.0. </b>
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.1. </b>
```go
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
@@ -73,7 +73,36 @@ func main() {
## Documentation
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
### <span id="index">Index<span>
- [Algorithm](#user-content-algorithm)
- [Compare](#user-content-compare)
- [Concurrency](#user-content-concurrency)
- [Condition](#user-content-condition)
- [Convertor](#user-content-convertor)
- [Cryptor](#user-content-cryptor)
- [Datetime](#user-content-datetime)
- [Datastructure](#user-content-datastructure)
- [Fileutil](#user-content-fileutil)
- [Formatter](#user-content-formatter)
- [Function](#user-content-function)
- [Maputil](#user-content-maputil)
- [Mathutil](#user-content-mathutil)
- [Netutil](#user-content-netutil)
- [Pointer](#user-content-pointer)
- [Random](#user-content-random)
- [Retry](#user-content-retry)
- [Slice](#user-content-slice)
- [Stream](#user-content-stream)
- [Structs](#user-content-structs)
- [Strutil](#user-content-strutil)
- [System](#user-content-system)
- [Tuple](#user-content-tuple)
- [Validator](#user-content-validator)
- [Xerror](#user-content-xerror)
<h3 id="algorithm">1. Algorithm package implements some basic algorithm. eg. sort, search. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/algorithm"
@@ -118,7 +147,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm.md#LRUCache)]
[[play](https://go.dev/play/p/-EZjgOURufP)]
### 2. Compare package provides a lightweight comparison function on any type.
<h3 id="compare"> 2. Compare package provides a lightweight comparison function on any type. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
```go
import "github.com/duke-git/lancet/v2/compare"
@@ -144,8 +173,10 @@ import "github.com/duke-git/lancet/v2/compare"
- **<big>GreaterOrEqual</big>** : Checks if value `left` less greater or equal than value `right`.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#GreaterOrEqual)]
[[play](https://go.dev/play/p/vx8mP0U8DFk)]
- **<big>InDelta</big>** : Checks if two values are equal or not within a delta.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare.md#InDelta)]
### 3. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async.
<h3 id="concurrency"> 3. Concurrency package contain some functions to support concurrent programming. eg, goroutine, channel, async. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
```go
import "github.com/duke-git/lancet/v2/concurrency"
@@ -184,7 +215,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)]
[[play](https://go.dev/play/p/3TQPKnCirrP)]
### 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
<h3 id="condition"> 4. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
```go
import "github.com/duke-git/lancet/v2/condition"
@@ -217,7 +248,7 @@ import "github.com/duke-git/lancet/v2/condition"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)]
[[play](https://go.dev/play/p/ElllPZY0guT)]
### 5. Convertor package contains some functions for data convertion.
<h3 id="convertor"> 5. Convertor package contains some functions for data convertion. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a> </h3>
```go
import "github.com/duke-git/lancet/v2/convertor"
@@ -284,10 +315,12 @@ import "github.com/duke-git/lancet/v2/convertor"
[[play](https://go.dev/play/p/syqw0-WG7Xd)]
- **<big>Utf8ToGbk</big>** : converts utf8 encoding data to GBK encoding data
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#Utf8ToGbk)]
[[play](https://go.dev/play/p/9FlIaFLArIL)]
- **<big>GbkToUtf8</big>** : converts GBK encoding data to utf8 encoding data.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#GbkToUtf8)]
[[play](https://go.dev/play/p/OphmHCN_9u8)]
### 6. Cryptor package is for data encryption and decryption.
<h3 id="cryptor"> 6. Cryptor package is for data encryption and decryption.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/cryptor"
@@ -358,29 +391,58 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>HmacMd5</big>** : return the md5 hmac hash of string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>HmacMd5WithBase64</big>** : return the md5 hmac hash of base64 string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5WithBase64)]
- **<big>HmacSha1</big>** : return the hmac hash of string use sha1.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha1)]
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
- **<big>HmacSha1WithBase64</big>** : return the hmac hash of string use sha1 with base64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha1WithBase64)]
[[play](https://go.dev/play/p/47JmmGrnF7B)]
- **<big>HmacSha256</big>** : return the hmac hash of string use sha256.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256)]
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
- **<big>HmacSha256WithBase64</big>** : return the hmac hash of string use sha256 with base64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha256WithBase64)]
[[play](https://go.dev/play/p/EKbkUvPTLwO)]
- **<big>HmacSha512</big>** : return the hmac hash of string use sha512.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512)]
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
- **<big>HmacSha512WithBase64</big>** : return the hmac hash of string use sha512 with base64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacSha512WithBase64)]
[[play](https://go.dev/play/p/c6dSe3E2ydU)]
- **<big>Md5Byte</big>** : return the md5 string of byte slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5Byte)]
[[play](https://go.dev/play/p/suraalH8lyC)]
- **<big>Md5ByteWithBase64</big>** : return the md5 string of byte slice with base64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5ByteWithBase64)]
[[play](https://go.dev/play/p/Tcb-Z7LN2ax)]
- **<big>Md5String</big>** : return the md5 value of string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5String)]
[[play](https://go.dev/play/p/1bLcVetbTOI)]
- **<big>Md5StringWithBase64</big>** : return the md5 value of string with base64.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5StringWithBase64)]
[[play](https://go.dev/play/p/Lx4gH7Vdr5_y)]
- **<big>Md5File</big>** : return the md5 value of file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Md5File)]
- **<big>Sha1</big>** : return the sha1 value (SHA-1 hash algorithm) of string.
- **<big>Sha1</big>** : return the sha1 value (SHA-1 hash algorithm) of base64 string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha1)]
[[play](https://go.dev/play/p/_m_uoD1deMT)]
- **<big>Sha1WithBase64</big>** : return the sha1 value (SHA-1 hash algorithm) of string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha1WithBase64)]
[[play](https://go.dev/play/p/fSyx-Gl2l2-)]
- **<big>Sha256</big>** : return the sha256 value (SHA-256 hash algorithm) of string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256)]
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
- **<big>Sha256WithBase64</big>** : return the sha256 value (SHA256 hash algorithm) of base64 string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha256WithBase64)]
[[play](https://go.dev/play/p/85IXJHIal1k)]
- **<big>Sha512</big>** : return the sha512 value (SHA-512 hash algorithm) of string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512)]
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
- **<big>Sha512WithBase64</big>** : return the sha512 value (SHA-512 hash algorithm) of base64 string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#Sha512WithBase64)]
[[play](https://go.dev/play/p/q_fY2rA-k5I)]
- **<big>GenerateRsaKey</big>** : create rsa private and public pemo file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#GenerateRsaKey)]
[[play](https://go.dev/play/p/zutRHrDqs0X)]
@@ -391,7 +453,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
### 7. Datetime package supports date and time format and compare.
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/datetime"
@@ -456,6 +518,12 @@ import "github.com/duke-git/lancet/v2/datetime"
- **<big>GetNowDateTime</big>** : return format yyyy-mm-dd hh-mm-ss of current datetime.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetNowDateTime)]
[[play](https://go.dev/play/p/pI4AqngD0al)]
- **<big>GetTodayStartTime</big>** : return the start time of today, format: yyyy-mm-dd 00:00:00.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetTodayStartTime)]
[[play](https://go.dev/play/p/84siyYF7t99)]
- **<big>GetTodayEndTime</big>** : return the end time of today, format: yyyy-mm-dd 23:59:59.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetTodayEndTime)]
[[play](https://go.dev/play/p/jjrLnfoqgn3)]
- **<big>GetZeroHourTimestamp</big>** : return timestamp of zero hour (timestamp of 00:00).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetZeroHourTimestamp)]
[[play](https://go.dev/play/p/QmL2oIaGE3q)]
@@ -504,12 +572,27 @@ import "github.com/duke-git/lancet/v2/datetime"
- **<big>IsWeekend</big>** : checks if passed time is weekend or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#IsWeekend)]
[[play](https://go.dev/play/p/cupRM5aZOIY)]
- **<big>NowDateOrTime</big>** : returns current datetime with specific format and timezone.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#NowDateOrTime)]
[[play](https://go.dev/play/p/EZ-begEjtT0)]
- **<big>Timestamp</big>** : returns current second timestamp.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#Timestamp)]
- **<big>TimestampMilli</big>** : returns current mill second timestamp.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampMilli)]
[[play](https://go.dev/play/p/4gvEusOTu1T)]
- **<big>TimestampMicro</big>** : returns current micro second timestamp.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampMicro)]
[[play](https://go.dev/play/p/2maANglKHQE)]
- **<big>TimestampNano</big>** : returns current nano second timestamp.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#TimestampNano)]
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
### 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
<h3 id="datastructure"> 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import list "github.com/duke-git/lancet/v2/datastructure/list"
import copyonwritelist "github.com/duke-git/lancet/v2/datastructure/copyonwritelist"
import link "github.com/duke-git/lancet/v2/datastructure/link"
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
@@ -523,6 +606,8 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
- **<big>List</big>** : a linear table, implemented with slice.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list.md)]
- **<big>CopyOnWriteList</big>** : a thread-safe list implementation that uses go slicing as its base.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/copyonwritelist.md)]
- **<big>Link</big>** : link list structure, contains singly link and doubly link.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/link.md)]
- **<big>Stack</big>** : stack structure(fifo), contains array stack and link stack.
@@ -538,7 +623,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
- **<big>Hashmap</big>** : hash map structure.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)]
### 9. Fileutil package implements some basic functions for file operations.
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -613,6 +698,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteCsvFile</big>** : write content to target csv file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteCsvFile)]
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
- **<big>WriteBytesToFile</big>** : write bytes to target file.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteBytesToFile)]
[[play](https://go.dev/play/p/s7QlDxMj3P8)]
@@ -620,8 +706,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteStringToFile)]
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
### 10. Formatter contains some functions for data formatting.
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -651,7 +736,7 @@ import "github.com/duke-git/lancet/v2/formatter"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
### 11. Function package can control the flow of function execution and support part of functional programming
<h3 id="function"> 11. Function package can control the flow of function execution and support part of functional programming.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/function"
@@ -687,7 +772,7 @@ import "github.com/duke-git/lancet/v2/function"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 12. Maputil package includes some functions to manipulate map.
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -758,8 +843,36 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>IsDisjoint</big>** : check two map are disjoint if they have no keys in common.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
- **<big>HasKey</big>** : checks if map has key or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#HasKey)]
[[play](https://go.dev/play/p/isZZHOsDhFc)]
- **<big>NewConcurrentMap</big>** : creates a ConcurrentMap with specific shard count.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#NewConcurrentMap)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_Set</big>** : set the value for a key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Set)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_Get</big>** : get the value stored in the map for a key, or nil if no.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Get)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_GetOrSet</big>** : returns the existing value for the key if present.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_GetOrSet)]
[[play](https://go.dev/play/p/aDcDApOK01a)]
- **<big>ConcurrentMap_Delete</big>** : delete the value for a key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Delete)]
[[play](https://go.dev/play/p/uTIJZYhpVMS)]
- **<big>ConcurrentMap_GetAndDelete</big>** :returns the existing value for the key if present and then delete the value for the key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_GetAndDelete)]
[[play](https://go.dev/play/p/ZyxeIXSZUiM)]
- **<big>ConcurrentMap_Has</big>** : checks if map has the value for a key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Has)]
[[play](https://go.dev/play/p/C8L4ul9TVwf)]
- **<big>ConcurrentMap_Range</big>** : calls iterator sequentially for each key and value present in each of the shards in the map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ConcurrentMap_Range)]
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
### 13. Mathutil package implements some functions for math calculation.
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/mathutil"
@@ -835,10 +948,12 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/TWMQlMywDsP)]
- **<big>Log</big>** : returns the logarithm of base n.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Log)]
[[play](https://go.dev/play/p/_d4bi8oyhat)]
- **<big>Sum</big>** : return sum of passed numbers.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sum)]
[[play](https://go.dev/play/p/1To2ImAMJA7)]
### 14. Netutil package contains functions to get net information and send http request.
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -911,7 +1026,31 @@ import "github.com/duke-git/lancet/v2/netutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsTelnetConnected)]
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
### 15. Random package implements some basic functions to generate random int and string.
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/pointer"
```
#### Function list:
- **<big>ExtractPointer</big>** : return the underlying value by the given interface type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#ExtractPointer)]
[[play](https://go.dev/play/p/D7HFjeWU2ZP)]
- **<big>Of</big>** : return a pointer to the value `v`.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#Of)]
[[play](https://go.dev/play/p/HFd70x4DrMj)]
- **<big>Unwrap</big>** : return the value from the pointer.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#Unwrap)]
[[play](https://go.dev/play/p/cgeu3g7cjWb)]
- **<big>UnwarpOr</big>** : UnwarpOr returns the value from the pointer or fallback if the pointer is nil.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#UnwrapOr)]
[[play](https://go.dev/play/p/mmNaLC38W8C)]
- **<big>UnwarpOrDefault</big>** : UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer.md#UnwrapOrDefault)]
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
<h3 id="random"> 16. Random package implements some basic functions to generate random int and string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/random"
@@ -945,8 +1084,9 @@ import "github.com/duke-git/lancet/v2/random"
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
- **<big>RandUniqueIntSlice</big>** : generate a slice of random int of length n that do not repeat.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUniqueIntSlice)]
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
### 16. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -970,7 +1110,7 @@ import "github.com/duke-git/lancet/v2/retry"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
### 17. Slice contains some functions to manipulate slice.
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/slice"
@@ -1182,8 +1322,12 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>KeyBy</big>** : converts a slice to a map based on a callback function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
- **<big>Join</big>** : join the slice item with specify separator.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Join)]
[[play](https://go.dev/play/p/huKzqwNDD7V)]
### 18. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited.
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/stream"
@@ -1270,7 +1414,7 @@ import "github.com/duke-git/lancet/v2/stream"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#ToSlice)]
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
### 19. Structs package provides several high level functions to manipulate struct, tag, and field.
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/structs"
@@ -1303,7 +1447,7 @@ import "github.com/duke-git/lancet/v2/structs"
- **<big>IsSlice</big>** : check if the field is a slice
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
### 20. Strutil package contains some functions to manipulate string.
<h3 id="strutil"> 21. Strutil package contains some functions to manipulate string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -1421,7 +1565,7 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>RemoveWhiteSpace</big>** : remove whitespace characters from a string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveWhiteSpace)]
### 21. System package contain some functions about os, runtime, shell command.
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/system"
@@ -1457,7 +1601,124 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
### 22. Validator package contains some functions for data validation.
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/tuple"
```
#### Function list:
- **<big>Tuple2</big>** : represents a 2 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple2)]
[[play](https://go.dev/play/p/3sHVqBQpLYN)]
- **<big>Tuple2_Unbox</big>** : returns values in Tuple2.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple2_Unbox)]
[[play](https://go.dev/play/p/0fD1qfCVwjm)]
- **<big>Zip2</big>** : create a slice of Tuple2, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip2)]
[[play](https://go.dev/play/p/4ncWJJ77Xio)]
- **<big>Unzip2</big>** : create a group of slice from a slice of Tuple2.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip2)]
[[play](https://go.dev/play/p/KBecr60feXb)]
- **<big>Tuple3</big>** : represents a 3 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple3)]
[[play](https://go.dev/play/p/FtH2sdCLlCf)]
- **<big>Tuple3_Unbox</big>** : returns values in Tuple3.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple3_Unbox)]
[[play](https://go.dev/play/p/YojLy-id1BS)]
- **<big>Zip3</big>** : create a slice of Tuple3, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip3)]
[[play](https://go.dev/play/p/97NgmsTILfu)]
- **<big>Unzip3</big>** : create a group of slice from a slice of Tuple3.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip3)]
[[play](https://go.dev/play/p/bba4cpAa7KO)]
- **<big>Tuple4</big>** : represents a 4 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple4)]
[[play](https://go.dev/play/p/D2EqDz096tk)]
- **<big>Tuple4_Unbox</big>** : returns values in Tuple4.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple4_Unbox)]
[[play](https://go.dev/play/p/ACj9YuACGgW)]
- **<big>Zip4</big>** : create a slice of Tuple4, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip4)]
[[play](https://go.dev/play/p/PEmTYVK5hL4)]
- **<big>Unzip4</big>** : create a group of slice from a slice of Tuple4.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip4)]
[[play](https://go.dev/play/p/rb8z4gyYSRN)]
- **<big>Tuple5</big>** : represents a 5 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple5)]
[[play](https://go.dev/play/p/2WndmVxPg-r)]
- **<big>Tuple5_Unbox</big>** : returns values in Tuple4.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple5_Unbox)]
[[play](https://go.dev/play/p/GyIyZHjCvoS)]
- **<big>Zip5</big>** : create a slice of Tuple5, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip5)]
[[play](https://go.dev/play/p/fCAAJLMfBIP)]
- **<big>Unzip5</big>** : create a group of slice from a slice of Tuple5.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip5)]
[[play](https://go.dev/play/p/gyl6vKfhqPb)]
- **<big>Tuple6</big>** : represents a 6 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple6)]
[[play](https://go.dev/play/p/VjqcCwEJZbs)]
- **<big>Tuple6_Unbox</big>** : returns values in Tuple6.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple6_Unbox)]
[[play](https://go.dev/play/p/FjIHV7lpxmW)]
- **<big>Zip6</big>** : create a slice of Tuple6, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip6)]
[[play](https://go.dev/play/p/oWPrnUYuFHo)]
- **<big>Unzip6</big>** : create a group of slice from a slice of Tuple6.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip6)]
[[play](https://go.dev/play/p/l41XFqCyh5E)]
- **<big>Tuple7</big>** : represents a 7 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple7)]
[[play](https://go.dev/play/p/dzAgv_Ezub9)]
- **<big>Tuple7_Unbox</big>** : returns values in Tuple7.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple7_Unbox)]
[[play](https://go.dev/play/p/R9I8qeDk0zs)]
- **<big>Zip7</big>** : create a slice of Tuple7, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip7)]
[[play](https://go.dev/play/p/WUJuo897Egf)]
- **<big>Unzip7</big>** : create a group of slice from a slice of Tuple7.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip7)]
[[play](https://go.dev/play/p/hws_P1Fr2j3)]
- **<big>Tuple8</big>** : represents a 8 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple8)]
[[play](https://go.dev/play/p/YA9S0rz3dRz)]
- **<big>Tuple8_Unbox</big>** : returns values in Tuple8.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple8_Unbox)]
[[play](https://go.dev/play/p/PRxLBBb4SMl)]
- **<big>Zip8</big>** : create a slice of Tuple8, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip8)]
[[play](https://go.dev/play/p/8V9jWkuJfaQ)]
- **<big>Unzip8</big>** : create a group of slice from a slice of Tuple8.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip8)]
[[play](https://go.dev/play/p/1SndOwGsZB4)]
- **<big>Tuple9</big>** : represents a 9 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple9)]
[[play](https://go.dev/play/p/yS2NGGtZpQr)]
- **<big>Tuple9_Unbox</big>** : returns values in Tuple9.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple9_Unbox)]
[[play](https://go.dev/play/p/oFJFGTAuOa8)]
- **<big>Zip9</big>** : create a slice of Tuple9, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip9)]
[[play](https://go.dev/play/p/cgsL15QYnfz)]
- **<big>Unzip9</big>** : create a group of slice from a slice of Tuple9.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip9)]
[[play](https://go.dev/play/p/91-BU_KURSA)]
- **<big>Tuple10</big>** : represents a 10 elemnets tuple.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple10)]
[[play](https://go.dev/play/p/799qqZg0hUv)]
- **<big>Tuple10_Unbox</big>** : returns values in Tuple10.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Tuple10_Unbox)]
[[play](https://go.dev/play/p/qfyx3x_X0Cu)]
- **<big>Zip10</big>** : create a slice of Tuple10, whose elements are correspond to the given slice elements.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Zip10)]
[[play](https://go.dev/play/p/YSR-2cXnrY4)]
- **<big>Unzip10</big>** : create a group of slice from a slice of Tuple10.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple.md#Unzip10)]
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
<h3 id="validator"> 24. Validator package contains some functions for data validation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -1565,7 +1826,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
### 23. xerror package implements helpers for errors.
<h3 id="xerror"> 25. Xerror package implements helpers for errors. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -4,7 +4,7 @@
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.2.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.2.5-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -23,7 +23,7 @@
## 特性
- 👏 全面、高效、可复用。
- 💪 500+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
- 💪 600+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
- 💅 只依赖 go 标准库和 golang.org/x。
- 🌍 所有导出函数单元测试覆盖率 100%。
@@ -37,7 +37,7 @@
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
```
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.0。</b>
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.1。</b>
```go
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
@@ -72,13 +72,41 @@ func main() {
## 文档
### 1. algorithm 包实现一些基本查找和排序算法。
### <span id="index">目录<span>
- [Algorithm](#user-content-algorithm)
- [Compare](#user-content-compare)
- [Concurrency](#user-content-concurrency)
- [Condition](#user-content-condition)
- [Convertor](#user-content-convertor)
- [Cryptor](#user-content-cryptor)
- [Datetime](#user-content-datetime)
- [Datastructure](#user-content-datastructure)
- [Fileutil](#user-content-fileutil)
- [Formatter](#user-content-formatter)
- [Function](#user-content-function)
- [Maputil](#user-content-maputil)
- [Mathutil](#user-content-mathutil)
- [Netutil](#user-content-netutil)
- [Pointer](#user-content-pointer)
- [Random](#user-content-random)
- [Retry](#user-content-retry)
- [Slice](#user-content-slice)
- [Stream](#user-content-stream)
- [Structs](#user-content-structs)
- [Strutil](#user-content-strutil)
- [System](#user-content-system)
- [Tuple](#user-content-tuple)
- [Validator](#user-content-validator)
- [Xerror](#user-content-xerror)
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/algorithm"
```
#### Function list:
#### 函数列表:
- **<big>BubbleSort</big>** : 使用冒泡排序算法对切片进行排序。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#BubbleSort)]
@@ -117,13 +145,13 @@ import "github.com/duke-git/lancet/v2/algorithm"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)]
[[play](https://go.dev/play/p/-EZjgOURufP)]
### 2. compare 包提供几个轻量级的类型比较函数。
<h3 id="compare"> 2. compare 包提供几个轻量级的类型比较函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/compare"
```
#### Function list:
#### 函数列表:
- **<big>Equal</big>** : 检查两个值是否相等(检查类型和值)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#Equal)]
@@ -143,14 +171,16 @@ import "github.com/duke-git/lancet/v2/compare"
- **<big>GreaterOrEqual</big>** : 验证参数`left`的值是否大于或等于参数`right`的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#GreaterOrEqual)]
[[play](https://go.dev/play/p/vx8mP0U8DFk)]
- **<big>InDelta</big>** : 检查增量内两个值是否相等。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/compare_zh-CN.md#InDelta)]
### 3. concurrency 包含一些支持并发编程的功能。例如goroutine, channel, async 等。
<h3 id="concurrency"> 3. concurrency 包含一些支持并发编程的功能。例如goroutine, channel, async 等。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/concurrency"
```
#### Function list:
#### 函数列表:
- **<big>NewChannel</big>** : 返回一个 Channel 指针实例。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#NewChannel)]
@@ -183,13 +213,13 @@ import "github.com/duke-git/lancet/v2/concurrency"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)]
[[play](https://go.dev/play/p/3TQPKnCirrP)]
### 4. condition 包含一些用于条件判断的函数。
<h3 id="condition"> 4. condition 包含一些用于条件判断的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/condition"
```
#### Function list:
#### 函数列表:
- **<big>Bool</big>** : 返回传入参数的 bool 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Bool)]
@@ -216,7 +246,7 @@ import "github.com/duke-git/lancet/v2/condition"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)]
[[play](https://go.dev/play/p/ElllPZY0guT)]
### 5. convertor 转换器包支持一些常见的数据类型转换。
<h3 id="convertor"> 5. convertor 转换器包支持一些常见的数据类型转换。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/convertor"
@@ -283,10 +313,12 @@ import "github.com/duke-git/lancet/v2/convertor"
[[play](https://go.dev/play/p/syqw0-WG7Xd)]
- **<big>Utf8ToGbk</big>** : utf8 编码转 GBK 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#Utf8ToGbk)]
[[play](https://go.dev/play/p/9FlIaFLArIL)]
- **<big>GbkToUtf8</big>** : GBK 编码转 utf8 编码。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#GbkToUtf8)]
[[play](https://go.dev/play/p/OphmHCN_9u8)]
### 6. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。
<h3 id="cryptor"> 6. cryptor 加密包支持数据加密和解密,获取 md5hash 值。支持 base64, md5, hmac, aes, des, rsa。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/cryptor"
@@ -357,29 +389,59 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>HmacMd5</big>** : 返回字符串 md5 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
- **<big>HmacMd5WithBase64</big>** : 获取字符串 md5 hmac base64 字符串值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacMd5WithBase64)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#HmacMd5WithBase64)]
- **<big>HmacSha1</big>** : 返回字符串 sha1 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1)]
[[play](https://go.dev/play/p/1UI4oQ4WXKM)]
- **<big>HmacSha1WithBase64</big>** : 获取字符串的 sha1 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha1WithBase64)]
[[play](https://go.dev/play/p/47JmmGrnF7B)]
- **<big>HmacSha256</big>** : 返回字符串 sha256 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256)]
[[play](https://go.dev/play/p/HhpwXxFhhC0)]
- **<big>HmacSha256WithBase64</big>** : 获取字符串 sha256 hmac base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha256WithBase64)]
[[play](https://go.dev/play/p/EKbkUvPTLwO)]
- **<big>HmacSha512</big>** : 返回字符串 sha256 hmac 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512)]
[[play](https://go.dev/play/p/59Od6m4A0Ud)]
- **<big>HmacSha512WithBase64</big>** : 获取字符串 sha512 hmac base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#HmacSha512WithBase64)]
[[play](https://go.dev/play/p/c6dSe3E2ydU)]
- **<big>Md5Byte</big>** : 返回 byte slice 的 md5 值.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5Byte)]
[[play](https://go.dev/play/p/suraalH8lyC)]
- **<big>Md5ByteWithBase64</big>** : 获取 byte slice 的 md5 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5ByteWithBase64)]
[[play](https://go.dev/play/p/Tcb-Z7LN2ax)]
- **<big>Md5String</big>** : 返回字符串 md5 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5String)]
[[play](https://go.dev/play/p/1bLcVetbTOI)]
- **<big>Md5StringWithBase64</big>** : 获取字符串 md5 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5StringWithBase64)]
[[play](https://go.dev/play/p/Lx4gH7Vdr5_y)]
- **<big>Md5File</big>** : 返回文件 md5 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Md5File)]
- **<big>Sha1</big>** : 返回字符串 sha1 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1)]
[[play](https://go.dev/play/p/_m_uoD1deMT)]
- **<big>Sha1WithBase64</big>** : 获取字符串 sha1 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha1WithBase64)]
[[play](https://go.dev/play/p/fSyx-Gl2l2-)]
- **<big>Sha256</big>** :返回字符串 sha256 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256)]
[[play](https://go.dev/play/p/tU9tfBMIAr1)]
- **<big>Sha256WithBase64</big>** : 获取字符串 sha256 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha256WithBase64)]
[[play](https://go.dev/play/p/85IXJHIal1k)]
- **<big>Sha512</big>** : 返回字符串 sha512 哈希值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512)]
[[play](https://go.dev/play/p/3WsvLYZxsHa)]
- **<big>Sha512WithBase64</big>** : 获取字符串 sha512 base64 值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#Sha512WithBase64)]
[[play](https://go.dev/play/p/q_fY2rA-k5I)]
- **<big>GenerateRsaKey</big>** : 在当前目录下创建 rsa 私钥文件和公钥文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#GenerateRsaKey)]
[[play](https://go.dev/play/p/zutRHrDqs0X)]
@@ -390,7 +452,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)]
[[play](https://go.dev/play/p/uef0q1fz53I)]
### 7. datetime 日期时间处理包,格式化日期,比较日期。
<h3 id="datetime"> 7. datetime 日期时间处理包,格式化日期,比较日期。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/datetime"
@@ -455,6 +517,12 @@ import "github.com/duke-git/lancet/v2/datetime"
- **<big>GetNowDateTime</big>** : 获取当时日期和时间返回格式yyyy-mm-dd hh:mm:ss。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetNowDateTime)]
[[play](https://go.dev/play/p/pI4AqngD0al)]
- **<big>GetTodayStartTime</big>** : 返回当天开始时间, 格式: yyyy-mm-dd 00:00:00。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetTodayStartTime)]
[[play](https://go.dev/play/p/84siyYF7t99)]
- **<big>GetTodayEndTime</big>** : 返回当天结束时间,格式: yyyy-mm-dd 23:59:59。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#GetTodayEndTime)]
[[play](https://go.dev/play/p/jjrLnfoqgn3)]
- **<big>GetZeroHourTimestamp</big>** : 获取零时时间戳(timestamp of 00:00)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#GetZeroHourTimestamp)]
[[play](https://go.dev/play/p/QmL2oIaGE3q)]
@@ -506,11 +574,27 @@ import "github.com/duke-git/lancet/v2/datetime"
- **<big>IsWeekend</big>** : 判断日期是否是周末。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#IsWeekend)]
[[play](https://go.dev/play/p/cupRM5aZOIY)]
- **<big>NowDateOrTime</big>** : 根据指定的格式和时区返回当前时间字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#NowDateOrTime)]
[[play](https://go.dev/play/p/EZ-begEjtT0)]
- **<big>Timestamp</big>** : 返回当前秒级时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#Timestamp)]
[[play](https://go.dev/play/p/iU5b7Vvjx6x)]
- **<big>TimestampMilli</big>** : 返回当前毫秒级时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampMilli)]
[[play](https://go.dev/play/p/4gvEusOTu1T)]
- **<big>TimestampMicro</big>** : 返回当前微秒级时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampMicro)]
[[play](https://go.dev/play/p/2maANglKHQE)]
- **<big>TimestampNano</big>** : 返回当前纳秒级时间戳。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#TimestampNano)]
[[play](https://go.dev/play/p/A9Oq_COrcCF)]
### 8. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
<h3 id="datastructure"> 8. datastructure 包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import list "github.com/duke-git/lancet/v2/datastructure/list"
import copyonwritelist "github.com/duke-git/lancet/v2/datastructure/copyonwritelist"
import link "github.com/duke-git/lancet/v2/datastructure/link"
import stack "github.com/duke-git/lancet/v2/datastructure/stack"
import queue "github.com/duke-git/lancet/v2/datastructure/queue"
@@ -520,10 +604,12 @@ import heap "github.com/duke-git/lancet/v2/datastructure/heap"
import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
```
#### Function list:
#### 函数列表:
- **<big>List</big>** : 线性表结构, 用切片实现。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list_zh-CN.md)]
- **<big>CopyOnWriteList</big>** : 是一个线程安全的 List 实现,底层使用 go 切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/copyonwritelist_zh-CN.md)]
- **<big>Link</big>** : 链表解构, 包括单链表和双向链表。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/link_zh-CN.md)]
- **<big>Stack</big>** : 栈结构(fifo), 包括数组栈和链表栈。
@@ -539,7 +625,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
- **<big>Hashmap</big>** : 哈希映射。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap_zh-CN.md)]
### 9. fileutil 包含文件基本操作。
<h3 id="fileutil"> 9. fileutil 包含文件基本操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -614,6 +700,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
- **<big>WriteCsvFile</big>** : 向 csv 文件写入内容。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteCsvFile)]
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteBytesToFile)]
[[play](https://go.dev/play/p/s7QlDxMj3P8)]
@@ -621,7 +708,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteStringToFile)]
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
### 10. formatter 格式化器包含一些数据格式化处理方法。
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -651,7 +738,7 @@ import "github.com/duke-git/lancet/v2/formatter"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
### 11. function 函数包控制函数执行流程,包含部分函数式编程。
<h3 id="function"> 11. function 函数包控制函数执行流程,包含部分函数式编程。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/function"
@@ -687,7 +774,7 @@ import "github.com/duke-git/lancet/v2/function"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
### 12. maputil 包括一些操作 map 的函数.
<h3 id="maputil"> 12. maputil 包括一些操作 map 的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -738,34 +825,61 @@ import "github.com/duke-git/lancet/v2/maputil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)]
[[play](https://go.dev/play/p/CBKdUc5FTW6)]
- **<big>ValuesBy</big>** : 创建一个切片,其元素是每个 map 的 value 调用 mapper 函数的结果。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#ValuesBy)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ValuesBy)]
[[play](https://go.dev/play/p/sg9-oRidh8f)]
- **<big>MapKeys</big>** : 操作 map 的每个 key然后转为新的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapKeys)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapKeys)]
[[play](https://go.dev/play/p/8scDxWeBDKd)]
- **<big>MapValues</big>** : 操作 map 的每个 value然后转为新的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#MapValues)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapValues)]
[[play](https://go.dev/play/p/g92aY3fc7Iw)]
- **<big>Entries</big>** : 将 map 转换为键/值对切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Entries)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Entries)]
[[play](https://go.dev/play/p/Ltb11LNcElY)]
- **<big>FromEntries</big>** : 基于键/值对的切片创建 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#FromEntries)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#FromEntries)]
[[play](https://go.dev/play/p/fTdu4sCNjQO)]
- **<big>Transform</big>** : 将 map 转换为其他类型的 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN#Transform)]
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Transform)]
[[play](https://go.dev/play/p/P6ovfToM3zj)]
- **<big>IsDisjoint</big>** : 验证两个 map 是否具有不同的 key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)]
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
- **<big>HasKey</big>** : 检查 map 是否包含某个 key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#HasKey)]
[[play](https://go.dev/play/p/isZZHOsDhFc)]
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#NewConcurrentMap)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_Set</big>** : 在 map 中设置 key 和 value。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Set)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_Get</big>** : 根据 key 获取 value, 如果不存在 key,返回零值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Get)]
[[play](https://go.dev/play/p/3PenTPETJT0)]
- **<big>ConcurrentMap_GetOrSet</big>** : 返回键的现有值(如果存在),否则,设置 key 并返回给定值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_GetOrSet)]
[[play](https://go.dev/play/p/aDcDApOK01a)]
- **<big>ConcurrentMap_Delete</big>** : 删除 key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Delete)]
[[play](https://go.dev/play/p/uTIJZYhpVMS)]
- **<big>ConcurrentMap_GetAndDelete</big>** :获取 key然后删除。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_GetAndDelete)]
[[play](https://go.dev/play/p/ZyxeIXSZUiM)]
- **<big>ConcurrentMap_Has</big>** : 验证是否包含 key。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Has)]
[[play](https://go.dev/play/p/C8L4ul9TVwf)]
- **<big>ConcurrentMap_Range</big>** : 为 map 中每个键和值顺序调用迭代器。 如果 iterator 返回 false则停止迭代。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ConcurrentMap_Range)]
[[play](https://go.dev/play/p/iqcy7P8P0Pr)]
### 13. mathutil 包实现了一些数学计算的函数。
<h3 id="mathutil"> 13. mathutil 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/mathutil"
```
#### Function list:
#### 函数列表:
- **<big>Average</big>** :计算平均数,可能需要对结果调用 RoundToFloat 方法四舍五入。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Average)]
@@ -835,10 +949,12 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/TWMQlMywDsP)]
- **<big>Log</big>** : 计算以 base 为底 n 的对数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Log)]
[[play](https://go.dev/play/p/_d4bi8oyhat)]
- **<big>Sum</big>** : 求传入参数之和。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sum)]
[[play](https://go.dev/play/p/1To2ImAMJA7)]
### 14. netutil 网络包支持获取 ip 地址,发送 http 请求。
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -911,7 +1027,31 @@ import "github.com/duke-git/lancet/v2/netutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsTelnetConnected)]
[[play](https://go.dev/play/p/yiLCGtQv_ZG)]
### 15. random 随机数生成器包,可以生成随机[]bytes, int, string。
<h3 id="pointer"> 15. pointer 包支持一些指针类型的操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/pointer"
```
#### 函数列表:
- **<big>ExtractPointer</big>** : 返回传入 interface 的底层值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#ExtractPointer)]
[[play](https://go.dev/play/p/D7HFjeWU2ZP)]
- **<big>Of</big>** : 返回传入参数的指针值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#Of)]
[[play](https://go.dev/play/p/HFd70x4DrMj)]
- **<big>Unwrap</big>** : 返回传入指针指向的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#Unwrap)]
[[play](https://go.dev/play/p/cgeu3g7cjWb)
- **<big>UnwarpOr</big>** : 返回指针的值,如果指针为零值,则返回 fallback。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#UnwrapOr)]
[[play](https://go.dev/play/p/mmNaLC38W8C)]
- **<big>UnwarpOrDefault</big>** : 返回指针的值,如果指针为零值,则返回相应零值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/pointer_zh-CN.md#UnwrapOrDefault)]
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
<h3 id="random"> 16. random 随机数生成器包,可以生成随机[]bytes, int, string。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/random"
@@ -943,10 +1083,11 @@ import "github.com/duke-git/lancet/v2/random"
- **<big>UUIdV4</big>** : 生成 UUID v4 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
- **<big>RandUniqueIntSlice</big>** : 生成一个不重复的长度为n的随机int切片。
- **<big>RandUniqueIntSlice</big>** : 生成一个不重复的长度为 n 的随机 int 切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUniqueIntSlice)]
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
### 16. retry 重试执行函数直到函数运行成功或被 context cancel。
<h3 id="retry"> 17. retry 重试执行函数直到函数运行成功或被 context cancel。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -970,7 +1111,7 @@ import "github.com/duke-git/lancet/v2/retry"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)]
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
### 17. slice 包含操作切片的方法集合。
<h3 id="slice"> 18. slice 包含操作切片的方法集合。&nbsp; &nbsp; &nbsp; &nbsp; [回到目录](#index)
```go
import "github.com/duke-git/lancet/v2/slice"
@@ -1182,14 +1323,17 @@ import "github.com/duke-git/lancet/v2/slice"
- **<big>KeyBy</big>** :将切片每个元素调用函数后转为 map。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
- **<big>Join</big>** : 用指定的分隔符链接切片元素。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Join)]
[[play](https://go.dev/play/p/huKzqwNDD7V)]
### 18. Stream 流,该包仅验证简单的 stream 实现,功能有限。
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/stream"
```
#### Function list:
#### 函数列表:
- **<big>Of</big>** : 创建元素为指定值的 stream。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Of)]
@@ -1270,13 +1414,13 @@ import "github.com/duke-git/lancet/v2/stream"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#ToSlice)]
[[play](https://go.dev/play/p/jI6_iZZuVFE)]
### 19. structs 提供操作 struct, tag, field 的相关函数。
<h3 id="structs"> 20. structs 提供操作 struct, tag, field 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/structs"
```
#### Function list:
#### 函数列表:
- **<big>New</big>** : `Struct`结构体的构造函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#New)]
@@ -1305,7 +1449,7 @@ import "github.com/duke-git/lancet/v2/structs"
- **<big>IsSlice</big>** : 判断属性是否是切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
### 20. strutil 包含字符串处理的相关函数。
<h3 id="strutil"> 21. strutil 包含字符串处理的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -1424,7 +1568,7 @@ import "github.com/duke-git/lancet/v2/strutil"
- **<big>RemoveWhiteSpace</big>** : 删除字符串中的空格。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveWhiteSpace)]
### 21. system 包含 os, runtime, shell command 的相关函数。
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/system"
@@ -1460,7 +1604,124 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
### 22. validator 验证器包,包含常用字符串格式验证函数。
<h3 id="tuple"> 23. Tuple 包实现一个元组数据类型。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/tuple"
```
#### 函数列表:
- **<big>Tuple2</big>** : 2 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple2)]
[[play](https://go.dev/play/p/3sHVqBQpLYN)]
- **<big>Tuple2_Unbox</big>** : 返回 2 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple2_Unbox)]
[[play](https://go.dev/play/p/0fD1qfCVwjm)]
- **<big>Zip2</big>** : 创建一个 Tuple2 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip2)]
[[play](https://go.dev/play/p/4ncWJJ77Xio)]
- **<big>Unzip2</big>** : 根据传入的 Tuple2 切片,创建一组和 Tuple2 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip2)]
[[play](https://go.dev/play/p/KBecr60feXb)]
- **<big>Tuple3</big>** : 3 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple3)]
[[play](https://go.dev/play/p/FtH2sdCLlCf)]
- **<big>Tuple3_Unbox</big>** : 返回 3 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple3_Unbox)]
[[play](https://go.dev/play/p/YojLy-id1BS)]
- **<big>Zip3</big>** : 创建一个 Tuple3 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip3)]
[[play](https://go.dev/play/p/97NgmsTILfu)]
- **<big>Unzip3</big>** : 根据传入的 Tuple3 切片,创建一组和 Tuple3 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip3)]
[[play](https://go.dev/play/p/bba4cpAa7KO)]
- **<big>Tuple4</big>** : 4 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple4)]
[[play](https://go.dev/play/p/D2EqDz096tk)]
- **<big>Tuple4_Unbox</big>** : 返回 4 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple4_Unbox)]
[[play](https://go.dev/play/p/ACj9YuACGgW)]
- **<big>Zip4</big>** : 创建一个 Tuple4 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip4)]
[[play](https://go.dev/play/p/PEmTYVK5hL4)]
- **<big>Unzip4</big>** : 根据传入的 Tuple4 切片,创建一组和 Tuple4 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip4)]
[[play](https://go.dev/play/p/rb8z4gyYSRN)]
- **<big>Tuple5</big>** : 5 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple5)]
[[play](https://go.dev/play/p/2WndmVxPg-r)]
- **<big>Tuple5_Unbox</big>** : 返回 5 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple5_Unbox)]
[[play](https://go.dev/play/p/GyIyZHjCvoS)]
- **<big>Zip5</big>** : 创建一个 Tuple5 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip5)]
[[play](https://go.dev/play/p/fCAAJLMfBIP)]
- **<big>Unzip5</big>** : 根据传入的 Tuple5 切片,创建一组和 Tuple5 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip5)]
[[play](https://go.dev/play/p/gyl6vKfhqPb)]
- **<big>Tuple6</big>** : 6 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple6)]
[[play](https://go.dev/play/p/VjqcCwEJZbs)]
- **<big>Tuple6_Unbox</big>** : 返回 6 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple6_Unbox)]
[[play](https://go.dev/play/p/FjIHV7lpxmW)]
- **<big>Zip6</big>** : 创建一个 Tuple6 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip6)]
[[play](https://go.dev/play/p/oWPrnUYuFHo)]
- **<big>Unzip6</big>** : 根据传入的 Tuple6 切片,创建一组和 Tuple6 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip6)]
[[play](https://go.dev/play/p/l41XFqCyh5E)]
- **<big>Tuple7</big>** : 7 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple7)]
[[play](https://go.dev/play/p/dzAgv_Ezub9)]
- **<big>Tuple7_Unbox</big>** : 返回 7 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple7_Unbox)]
[[play](https://go.dev/play/p/R9I8qeDk0zs)]
- **<big>Zip7</big>** : 创建一个 Tuple7 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip7)]
[[play](https://go.dev/play/p/WUJuo897Egf)]
- **<big>Unzip7</big>** : 根据传入的 Tuple7 切片,创建一组和 Tuple7 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip7)]
[[play](https://go.dev/play/p/hws_P1Fr2j3)]
- **<big>Tuple8</big>** : 8 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple8)]
[[play](https://go.dev/play/p/YA9S0rz3dRz)]
- **<big>Tuple8_Unbox</big>** : 返回 8 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple8_Unbox)]
[[play](https://go.dev/play/p/PRxLBBb4SMl)]
- **<big>Zip8</big>** : 创建一个 Tuple8 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip8)]
[[play](https://go.dev/play/p/8V9jWkuJfaQ)]
- **<big>Unzip8</big>** : 根据传入的 Tuple8 切片,创建一组和 Tuple8 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip8)]
[[play](https://go.dev/play/p/1SndOwGsZB4)]
- **<big>Tuple9</big>** : 9 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple9)]
[[play](https://go.dev/play/p/yS2NGGtZpQr)]
- **<big>Tuple9_Unbox</big>** : 返回 9 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple9_Unbox)]
[[play](https://go.dev/play/p/oFJFGTAuOa8)]
- **<big>Zip9</big>** : 创建一个 Tuple9 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip9)]
[[play](https://go.dev/play/p/cgsL15QYnfz)]
- **<big>Unzip9</big>** : 根据传入的 Tuple9 切片,创建一组和 Tuple9 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip9)]
[[play](https://go.dev/play/p/91-BU_KURSA)]
- **<big>Tuple10</big>** : 10 元元组
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple10)]
[[play](https://go.dev/play/p/799qqZg0hUv)]
- **<big>Tuple10_Unbox</big>** : 返回 10 元元组的字段值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Tuple10_Unbox)]
[[play](https://go.dev/play/p/qfyx3x_X0Cu)]
- **<big>Zip10</big>** : 创建一个 Tuple10 元组切片, 其中元组的元素和传入切片元素相对应。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Zip10)]
[[play](https://go.dev/play/p/YSR-2cXnrY4)]
- **<big>Unzip10</big>** : 根据传入的 Tuple10 切片,创建一组和 Tuple10 元素相对应的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/tuple_zh-CN.md#Unzip10)]
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
<h3 id="validator"> 24. validator 验证器包,包含常用字符串格式验证函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -1568,7 +1829,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
### 23. xerror 包实现一些错误处理函数
<h3 id="xerror"> 25. xerror 包实现一些错误处理函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -7,6 +7,7 @@ import (
)
func TestLRUCache(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLRUCache")
cache := NewLRUCache[int, int](3)

View File

@@ -7,6 +7,7 @@ import (
)
func TestLinearSearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestLinearSearch")
numbers := []int{3, 4, 5, 3, 2, 1}
@@ -19,6 +20,7 @@ func TestLinearSearch(t *testing.T) {
}
func TestBinarySearch(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBinarySearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}

View File

@@ -46,6 +46,7 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
}
func TestBubbleSortForStructSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
peoples := []people{
@@ -65,6 +66,7 @@ func TestBubbleSortForStructSlice(t *testing.T) {
}
func TestBubbleSortForIntSlice(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
@@ -75,6 +77,7 @@ func TestBubbleSortForIntSlice(t *testing.T) {
}
func TestInsertionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestInsertionSort")
peoples := []people{
@@ -94,6 +97,7 @@ func TestInsertionSort(t *testing.T) {
}
func TestSelectionSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestSelectionSort")
peoples := []people{
@@ -113,6 +117,7 @@ func TestSelectionSort(t *testing.T) {
}
func TestShellSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestShellSort")
peoples := []people{
@@ -132,6 +137,7 @@ func TestShellSort(t *testing.T) {
}
func TestQuickSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestQuickSort")
peoples := []people{
@@ -151,6 +157,7 @@ func TestQuickSort(t *testing.T) {
}
func TestHeapSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestHeapSort")
peoples := []people{
@@ -170,6 +177,7 @@ func TestHeapSort(t *testing.T) {
}
func TestMergeSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestMergeSort")
peoples := []people{
@@ -189,6 +197,7 @@ func TestMergeSort(t *testing.T) {
}
func TestCountSort(t *testing.T) {
t.Parallel()
asssert := internal.NewAssert(t, "TestCountSort")
peoples := []people{

View File

@@ -10,6 +10,8 @@ import (
"time"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/mathutil"
"golang.org/x/exp/constraints"
)
// operator type
@@ -62,3 +64,8 @@ func LessOrEqual(left, right any) bool {
func GreaterOrEqual(left, right any) bool {
return compareValue(greaterOrEqual, left, right)
}
// InDelta checks if two values are equal or not within a delta.
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool {
return float64(mathutil.Abs(left-right)) <= delta
}

View File

@@ -168,3 +168,29 @@ func ExampleGreaterOrEqual() {
// false
// false
}
func ExampleInDelta() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}

View File

@@ -8,6 +8,7 @@ import (
)
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
assert.Equal(true, Equal(1, 1))
@@ -60,6 +61,7 @@ func TestEqual(t *testing.T) {
}
func TestEqualValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqualValue")
assert.Equal(true, EqualValue(1, 1))
@@ -70,6 +72,7 @@ func TestEqualValue(t *testing.T) {
}
func TestLessThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessThan")
assert.Equal(true, LessThan(1, 2))
@@ -85,6 +88,7 @@ func TestLessThan(t *testing.T) {
}
func TestGreaterThan(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterThan(2, 1))
@@ -101,6 +105,7 @@ func TestGreaterThan(t *testing.T) {
}
func TestLessOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLessOrEqual")
assert.Equal(true, LessOrEqual(1, 2))
@@ -117,6 +122,7 @@ func TestLessOrEqual(t *testing.T) {
}
func TestGreaterOrEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGreaterThan")
assert.Equal(true, GreaterOrEqual(2, 1))
@@ -132,3 +138,19 @@ func TestGreaterOrEqual(t *testing.T) {
assert.Equal(false, GreaterOrEqual(int64(2), 1))
assert.Equal(false, GreaterOrEqual("b", "c"))
}
func TestInDelta(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInDelta")
assert.Equal(true, InDelta(1, 1, 0))
assert.Equal(false, InDelta(1, 2, 0))
assert.Equal(true, InDelta(2.0/3.0, 0.66667, 0.001))
assert.Equal(false, InDelta(2.0/3.0, 0.0, 0.001))
assert.Equal(false, InDelta(float64(74.96)-float64(20.48), 54.48, 0))
assert.Equal(true, InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14))
assert.Equal(false, InDelta(float64(float32(80.45)), float64(80.45), 0))
assert.Equal(true, InDelta(float64(float32(80.45)), float64(80.45), 1e-5))
}

View File

@@ -9,6 +9,7 @@ import (
)
func TestGenerate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGenerate")
ctx, cancel := context.WithCancel(context.Background())
@@ -23,6 +24,7 @@ func TestGenerate(t *testing.T) {
}
func TestRepeat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeat")
ctx, cancel := context.WithCancel(context.Background())
@@ -39,6 +41,7 @@ func TestRepeat(t *testing.T) {
}
func TestRepeatFn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeatFn")
ctx, cancel := context.WithCancel(context.Background())
@@ -57,6 +60,7 @@ func TestRepeatFn(t *testing.T) {
}
func TestTake(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTake")
ctx, cancel := context.WithCancel(context.Background())
@@ -79,6 +83,7 @@ func TestTake(t *testing.T) {
}
func TestFanIn(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFanIn")
ctx, cancel := context.WithCancel(context.Background())
@@ -101,6 +106,7 @@ func TestFanIn(t *testing.T) {
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
sig := func(after time.Duration) <-chan any {
@@ -127,6 +133,7 @@ func TestOr(t *testing.T) {
}
func TestOrDone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOrDone")
ctx, cancel := context.WithCancel(context.Background())
@@ -141,6 +148,7 @@ func TestOrDone(t *testing.T) {
}
func TestTee(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTee")
ctx, cancel := context.WithCancel(context.Background())
@@ -159,6 +167,7 @@ func TestTee(t *testing.T) {
}
func TestBridge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBridge")
ctx, cancel := context.WithCancel(context.Background())

View File

@@ -11,6 +11,8 @@ import (
type TestStruct struct{}
func TestBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBool")
// bool
@@ -63,6 +65,8 @@ func TestBool(t *testing.T) {
}
func TestAnd(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAnd")
assert.Equal(false, And(0, 1))
assert.Equal(false, And(0, ""))
@@ -71,6 +75,8 @@ func TestAnd(t *testing.T) {
}
func TestOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Or(0, ""))
assert.Equal(true, Or(0, 1))
@@ -79,6 +85,8 @@ func TestOr(t *testing.T) {
}
func TestXor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Xor(0, 0))
assert.Equal(true, Xor(0, 1))
@@ -87,6 +95,8 @@ func TestXor(t *testing.T) {
}
func TestNor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNor")
assert.Equal(true, Nor(0, 0))
assert.Equal(false, Nor(0, 1))
@@ -95,6 +105,8 @@ func TestNor(t *testing.T) {
}
func TestXnor(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestXnor")
assert.Equal(true, Xnor(0, 0))
assert.Equal(false, Xnor(0, 1))
@@ -103,6 +115,8 @@ func TestXnor(t *testing.T) {
}
func TestNand(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNand")
assert.Equal(true, Nand(0, 0))
assert.Equal(true, Nand(0, 1))
@@ -111,7 +125,10 @@ func TestNand(t *testing.T) {
}
func TestTernaryOperator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TernaryOperator")
trueValue := "1"
falseValue := "0"

View File

@@ -380,7 +380,7 @@ func ToInterface(v reflect.Value) (value interface{}, ok bool) {
}
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
// Play: todo
// Play: https://go.dev/play/p/9FlIaFLArIL
func Utf8ToGbk(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
b, err := io.ReadAll(r)
@@ -388,7 +388,7 @@ func Utf8ToGbk(bs []byte) ([]byte, error) {
}
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
// Play: todo
// Play: https://go.dev/play/p/OphmHCN_9u8
func GbkToUtf8(bs []byte) ([]byte, error) {
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
b, err := io.ReadAll(r)

View File

@@ -13,6 +13,8 @@ import (
)
func TestToChar(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChar")
cases := []string{"", "abc", "1 2#3"}
@@ -27,6 +29,8 @@ func TestToChar(t *testing.T) {
}
func TestToChannel(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToChannel")
ch := ToChannel([]int{1, 2, 3})
@@ -39,6 +43,8 @@ func TestToChannel(t *testing.T) {
}
func TestToBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBool")
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
@@ -51,6 +57,8 @@ func TestToBool(t *testing.T) {
}
func TestToBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToBytes")
cases := []any{
@@ -77,6 +85,8 @@ func TestToBytes(t *testing.T) {
}
func TestToInt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInt")
cases := []any{"123", "-123", 123,
@@ -93,6 +103,8 @@ func TestToInt(t *testing.T) {
}
func TestToFloat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFloat")
cases := []any{
@@ -111,6 +123,8 @@ func TestToFloat(t *testing.T) {
}
func TestToString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToString")
aMap := make(map[string]int)
@@ -146,6 +160,8 @@ func TestToString(t *testing.T) {
}
}
func TestToJson(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToJson")
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
@@ -161,6 +177,8 @@ func TestToJson(t *testing.T) {
}
func TestToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToMap")
type Message struct {
@@ -180,6 +198,8 @@ func TestToMap(t *testing.T) {
}
func TestStructToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStructToMap")
t.Run("StructToMap", func(_ *testing.T) {
@@ -215,6 +235,8 @@ func TestStructToMap(t *testing.T) {
}
func TestMapToSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapToSlice")
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
@@ -229,6 +251,8 @@ func TestMapToSlice(t *testing.T) {
}
func TestColorHexToRGB(t *testing.T) {
t.Parallel()
colorHex := "#003366"
r, g, b := ColorHexToRGB(colorHex)
colorRGB := fmt.Sprintf("%d,%d,%d", r, g, b)
@@ -239,6 +263,8 @@ func TestColorHexToRGB(t *testing.T) {
}
func TestColorRGBToHex(t *testing.T) {
t.Parallel()
r := 0
g := 51
b := 102
@@ -250,6 +276,8 @@ func TestColorRGBToHex(t *testing.T) {
}
func TestToPointer(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToPointer")
result := ToPointer(123)
@@ -257,6 +285,8 @@ func TestToPointer(t *testing.T) {
}
func TestEncodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEncodeByte")
byteData, _ := EncodeByte("abc")
@@ -266,6 +296,8 @@ func TestEncodeByte(t *testing.T) {
}
func TestDecodeByte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDecodeByte")
var obj string
@@ -276,6 +308,8 @@ func TestDecodeByte(t *testing.T) {
}
func TestDeepClone(t *testing.T) {
t.Parallel()
// assert := internal.NewAssert(t, "TestDeepClone")
type Struct struct {
@@ -319,6 +353,8 @@ func TestDeepClone(t *testing.T) {
}
func TestCopyProperties(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCopyProperties")
type Disk struct {
@@ -371,6 +407,8 @@ func TestCopyProperties(t *testing.T) {
}
func TestToInterface(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToInterface")
cases := []reflect.Value{
@@ -400,6 +438,7 @@ func TestToInterface(t *testing.T) {
}
func TestUtf8ToGbk(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUtf8ToGbk")
utf8Data := []byte("hello")
@@ -411,6 +450,7 @@ func TestUtf8ToGbk(t *testing.T) {
}
func TestGbkToUtf8(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGbkToUtf8")
gbkData, err := Utf8ToGbk([]byte("hello"))

View File

@@ -40,6 +40,30 @@ func Md5String(s string) string {
return hex.EncodeToString(h.Sum(nil))
}
// Md5StringWithBase64 return the md5 value of string with base64.
// Play: https://go.dev/play/p/Lx4gH7Vdr5_y
func Md5StringWithBase64(s string) string {
h := md5.New()
h.Write([]byte(s))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5Byte return the md5 string of byte slice.
// Play: https://go.dev/play/p/suraalH8lyC
func Md5Byte(data []byte) string {
h := md5.New()
h.Write(data)
return hex.EncodeToString(h.Sum(nil))
}
// Md5ByteWithBase64 return the md5 string of byte slice with base64.
// Play: https://go.dev/play/p/Tcb-Z7LN2ax
func Md5ByteWithBase64(data []byte) string {
h := md5.New()
h.Write(data)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
// Md5File return the md5 value of file.
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
@@ -74,56 +98,112 @@ func Md5File(filename string) (string, error) {
// HmacMd5 return the hmac hash of string use md5.
// Play: https://go.dev/play/p/uef0q1fz53I
func HmacMd5(data, key string) string {
func HmacMd5(str, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacMd5WithBase64 return the hmac hash of string use md5 with base64.
// todo
func HmacMd5WithBase64(data, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1 return the hmac hash of string use sha1.
// Play: https://go.dev/play/p/1UI4oQ4WXKM
func HmacSha1(data, key string) string {
func HmacSha1(str, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1WithBase64 return the hmac hash of string use sha1 with base64.
// Play: https://go.dev/play/p/47JmmGrnF7B
func HmacSha1WithBase64(str, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256.
// Play: https://go.dev/play/p/HhpwXxFhhC0
func HmacSha256(data, key string) string {
func HmacSha256(str, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256WithBase64 return the hmac hash of string use sha256 with base64.
// Play: https://go.dev/play/p/EKbkUvPTLwO
func HmacSha256WithBase64(str, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512.
// Play: https://go.dev/play/p/59Od6m4A0Ud
func HmacSha512(data, key string) string {
func HmacSha512(str, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(data))
h.Write([]byte(str))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512WithBase64 return the hmac hash of string use sha512 with base64.
// Play: https://go.dev/play/p/c6dSe3E2ydU
func HmacSha512WithBase64(str, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(str))
return base64.StdEncoding.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
// Play: https://go.dev/play/p/_m_uoD1deMT
func Sha1(data string) string {
func Sha1(str string) string {
sha1 := sha1.New()
sha1.Write([]byte(data))
sha1.Write([]byte(str))
return hex.EncodeToString(sha1.Sum([]byte("")))
}
// Sha1WithBase64 return the sha1 value (SHA-1 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/fSyx-Gl2l2-
func Sha1WithBase64(str string) string {
sha1 := sha1.New()
sha1.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
// Play: https://go.dev/play/p/tU9tfBMIAr1
func Sha256(data string) string {
func Sha256(str string) string {
sha256 := sha256.New()
sha256.Write([]byte(data))
sha256.Write([]byte(str))
return hex.EncodeToString(sha256.Sum([]byte("")))
}
// Sha256WithBase64 return the sha256 value (SHA256 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/85IXJHIal1k
func Sha256WithBase64(str string) string {
sha256 := sha256.New()
sha256.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
// Play: https://go.dev/play/p/3WsvLYZxsHa
func Sha512(data string) string {
func Sha512(str string) string {
sha512 := sha512.New()
sha512.Write([]byte(data))
sha512.Write([]byte(str))
return hex.EncodeToString(sha512.Sum([]byte("")))
}
// Sha512WithBase64 return the sha512 value (SHA512 hash algorithm) of base64 string.
// Play: https://go.dev/play/p/q_fY2rA-k5I
func Sha512WithBase64(str string) string {
sha512 := sha512.New()
sha512.Write([]byte(str))
return base64.StdEncoding.EncodeToString(sha512.Sum([]byte("")))
}

View File

@@ -7,21 +7,51 @@ import (
)
func TestBase64StdEncode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdEncode")
assert.Equal("aGVsbG8gd29ybGQ=", Base64StdEncode("hello world"))
}
func TestBase64StdDecode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBase64StdDecode")
assert.Equal("hello world", Base64StdDecode("aGVsbG8gd29ybGQ="))
}
func TestMd5String(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5String")
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
}
func TestMd5StringWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5StringWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5StringWithBase64("hello"))
}
func TestMd5Byte(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5Byte")
data := []byte{'a'}
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
}
func TestMd5ByteWithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMd5ByteWithBase64")
assert.Equal("XUFAKrxLKna5cZ2REBfFkg==", Md5ByteWithBase64([]byte("hello")))
}
func TestMd5File(t *testing.T) {
t.Parallel()
fileMd5, err := Md5File("./basic.go")
assert := internal.NewAssert(t, "TestMd5File")
assert.IsNotNil(fileMd5)
@@ -29,11 +59,22 @@ func TestMd5File(t *testing.T) {
}
func TestHmacMd5(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5")
assert.Equal("5f4c9faaff0a1ad3007d9ddc06abe36d", HmacMd5("hello world", "12345"))
}
func TestHmacMd5WithBase64(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHmacMd5WithBase64")
assert.Equal("6DQwbquJLYclJdSRinpjmg==", HmacMd5WithBase64("hello", "12345"))
}
func TestHmacSha1(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha1 := HmacSha1(s, key)
@@ -43,17 +84,45 @@ func TestHmacSha1(t *testing.T) {
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
s := "hello world"
func TestHmacSha1WithBase64(t *testing.T) {
t.Parallel()
s := "hello"
key := "12345"
hmacSha256 := HmacSha256(s, key)
hmacSha1 := HmacSha1WithBase64(s, key)
expected := "XGqdsMzLkuNu0DI/0Jt/k23prOA="
assert := internal.NewAssert(t, "TestHmacSha1")
assert.Equal(expected, hmacSha1)
}
func TestHmacSha256(t *testing.T) {
t.Parallel()
str := "hello world"
key := "12345"
hmacSha256 := HmacSha256(str, key)
expected := "9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8"
assert := internal.NewAssert(t, "TestHmacSha256")
assert.Equal(expected, hmacSha256)
}
func TestHmacSha256WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
expected := "MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU="
assert := internal.NewAssert(t, "TestHmacSha256WithBase64")
assert.Equal(expected, hms)
}
func TestHmacSha512(t *testing.T) {
t.Parallel()
s := "hello world"
key := "12345"
hmacSha512 := HmacSha512(s, key)
@@ -63,7 +132,21 @@ func TestHmacSha512(t *testing.T) {
assert.Equal(expected, hmacSha512)
}
func TestHmacSha512WithBase64(t *testing.T) {
t.Parallel()
str := "hello"
key := "12345"
hms := HmacSha512WithBase64(str, key)
expected := "3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A=="
assert := internal.NewAssert(t, "TestHmacSha512WithBase64")
assert.Equal(expected, hms)
}
func TestSha1(t *testing.T) {
t.Parallel()
s := "hello world"
sha1 := Sha1(s)
expected := "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
@@ -72,7 +155,19 @@ func TestSha1(t *testing.T) {
assert.Equal(expected, sha1)
}
func TestSha1WithBase64(t *testing.T) {
t.Parallel()
str := Sha1WithBase64("hello")
expected := "qvTGHdzF6KLavt4PO0gs2a6pQ00="
assert := internal.NewAssert(t, "TestSha1WithBase64")
assert.Equal(expected, str)
}
func TestSha256(t *testing.T) {
t.Parallel()
s := "hello world"
sha256 := Sha256(s)
expected := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
@@ -81,7 +176,19 @@ func TestSha256(t *testing.T) {
assert.Equal(expected, sha256)
}
func TestSha256WithBase64(t *testing.T) {
t.Parallel()
str := Sha256WithBase64("hello")
expected := "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
assert := internal.NewAssert(t, "TestSha256WithBase64")
assert.Equal(expected, str)
}
func TestSha512(t *testing.T) {
t.Parallel()
s := "hello world"
sha512 := Sha512(s)
expected := "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
@@ -89,3 +196,13 @@ func TestSha512(t *testing.T) {
assert := internal.NewAssert(t, "TestSha512")
assert.Equal(expected, sha512)
}
func TestSha512WithBase64(t *testing.T) {
t.Parallel()
str := Sha512WithBase64("hello")
expected := "m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
assert := internal.NewAssert(t, "TestSha512WithBase64")
assert.Equal(expected, str)
}

View File

@@ -322,89 +322,165 @@ func ExampleHmacMd5() {
key := "12345"
hms := HmacMd5(str, key)
fmt.Println(hms)
// Output:
// e834306eab892d872525d4918a7a639a
}
func ExampleHmacMd5WithBase64() {
str := "hello"
key := "12345"
hms := HmacMd5WithBase64(str, key)
fmt.Println(hms)
// Output:
// 6DQwbquJLYclJdSRinpjmg==
}
func ExampleHmacSha1() {
str := "hello"
key := "12345"
hms := HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
func ExampleHmacSha1WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha1WithBase64(str, key)
fmt.Println(hms)
// Output:
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
}
func ExampleHmacSha256() {
str := "hello"
key := "12345"
hms := HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
}
func ExampleHmacSha256WithBase64() {
str := "hello"
key := "12345"
hms := HmacSha256WithBase64(str, key)
fmt.Println(hms)
// Output:
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
}
func ExampleHmacSha512() {
str := "hello"
key := "12345"
hms := HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
}
func ExampleMd5String() {
func ExampleHmacSha512WithBase64() {
str := "hello"
key := "12345"
md5Str := Md5String(str)
hms := HmacSha512WithBase64(str, key)
fmt.Println(hms)
// Output:
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
}
func ExampleMd5String() {
md5Str := Md5String("hello")
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
}
func ExampleMd5StringWithBase64() {
md5Str := Md5StringWithBase64("hello")
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleMd5Byte() {
md5Str := Md5Byte([]byte{'a'})
fmt.Println(md5Str)
// Output:
// 0cc175b9c0f1b6a831c399e269772661
}
func ExampleMd5ByteWithBase64() {
md5Str := Md5ByteWithBase64([]byte("hello"))
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
func ExampleSha1() {
str := "hello"
result := Sha1(str)
result := Sha1("hello")
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
}
func ExampleSha1WithBase64() {
result := Sha1WithBase64("hello")
fmt.Println(result)
// Output:
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
}
func ExampleSha256() {
str := "hello"
result := Sha256(str)
result := Sha256("hello")
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}
func ExampleSha256WithBase64() {
result := Sha256WithBase64("hello")
fmt.Println(result)
// Output:
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
}
func ExampleSha512() {
str := "hello"
result := Sha512(str)
result := Sha512("hello")
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
}
func ExampleSha512WithBase64() {
result := Sha512WithBase64("hello")
fmt.Println(result)
// Output:
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestAesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
@@ -18,6 +20,8 @@ func TestAesEcbEncrypt(t *testing.T) {
}
func TestAesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
@@ -29,6 +33,8 @@ func TestAesCbcEncrypt(t *testing.T) {
}
func TestAesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
@@ -40,6 +46,8 @@ func TestAesCtrCrypt(t *testing.T) {
}
func TestAesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
@@ -51,6 +59,8 @@ func TestAesCfbEncrypt(t *testing.T) {
}
func TestAesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefghijklmnop"
@@ -62,6 +72,8 @@ func TestAesOfbEncrypt(t *testing.T) {
}
func TestDesEcbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
@@ -73,6 +85,8 @@ func TestDesEcbEncrypt(t *testing.T) {
}
func TestDesCbcEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
@@ -84,6 +98,8 @@ func TestDesCbcEncrypt(t *testing.T) {
}
func TestDesCtrCrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
@@ -95,6 +111,8 @@ func TestDesCtrCrypt(t *testing.T) {
}
func TestDesCfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
@@ -106,6 +124,8 @@ func TestDesCfbEncrypt(t *testing.T) {
}
func TestDesOfbEncrypt(t *testing.T) {
t.Parallel()
data := "hello world"
key := "abcdefgh"
@@ -117,6 +137,8 @@ func TestDesOfbEncrypt(t *testing.T) {
}
func TestRsaEncrypt(t *testing.T) {
t.Parallel()
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil {
t.FailNow()

View File

@@ -7,6 +7,7 @@ package datastructure
import (
"fmt"
"hash/fnv"
"reflect"
)
var defaultMapCapacity uint64 = 1 << 10
@@ -45,13 +46,24 @@ func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
func (hm *HashMap) Get(key any) any {
hashValue := hm.hash(key)
node := hm.table[hashValue]
if node != nil {
return node.value
for node != nil {
if reflect.DeepEqual(node.key, key) {
return node.value
}
node = node.next
}
return nil
}
// GetOrDefault return the value of given key in hashmap, if not found return default value
func (hm *HashMap) GetOrDefault(key any, defaultValue any) any {
value := hm.Get(key)
if value == nil {
return defaultValue
}
return value
}
// Put new key value in hashmap
func (hm *HashMap) Put(key any, value any) {
hm.putValue(hm.hash(key), key, value)
@@ -90,7 +102,13 @@ func (hm *HashMap) Delete(key any) {
// Contains checks if given key is in hashmap or not
func (hm *HashMap) Contains(key any) bool {
node := hm.table[hm.hash(key)]
return node != nil
for node != nil {
if reflect.DeepEqual(node.key, key) {
return true
}
node = node.next
}
return false
}
// Iterate executes iteratee funcation for every key and value pair of hashmap (random order)

View File

@@ -32,6 +32,8 @@ func TestHashMap_Resize(t *testing.T) {
}
func TestHashMap_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Delete")
hm := NewHashMap()
@@ -44,6 +46,8 @@ func TestHashMap_Delete(t *testing.T) {
}
func TestHashMap_Contains(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Contains")
hm := NewHashMap()
@@ -54,6 +58,8 @@ func TestHashMap_Contains(t *testing.T) {
}
func TestHashMap_KeysValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_KeysValues")
hm := NewHashMap()
@@ -68,3 +74,34 @@ func TestHashMap_KeysValues(t *testing.T) {
assert.Equal(3, len(values))
assert.Equal(3, len(keys))
}
func TestHashMap_Keys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_Keys")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
assert.Equal(3, len(keys))
}
func TestHashMap_GetOrDefault(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHashMap_GetOrDefault")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
assert.Equal(1, hm.GetOrDefault("a", 5))
assert.Equal(5, hm.GetOrDefault("d", 5))
}

View File

@@ -21,6 +21,8 @@ func (c *intComparator) Compare(v1, v2 any) int {
}
func TestMaxHeap_BuildMaxHeap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_BuildMaxHeap")
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
@@ -33,6 +35,8 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
}
func TestMaxHeap_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Push")
heap := NewMaxHeap[int](&intComparator{})
@@ -51,6 +55,8 @@ func TestMaxHeap_Push(t *testing.T) {
}
func TestMaxHeap_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Pop")
heap := NewMaxHeap[int](&intComparator{})
@@ -70,6 +76,8 @@ func TestMaxHeap_Pop(t *testing.T) {
}
func TestMaxHeap_Peek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMaxHeap_Peek")
heap := NewMaxHeap[int](&intComparator{})

View File

@@ -7,6 +7,8 @@ import (
)
func TestDoublyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtFirst")
link := NewDoublyLink[int]()
@@ -22,6 +24,8 @@ func TestDoublyLink_InsertAtFirst(t *testing.T) {
}
func TestDoublyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAtTail")
link := NewDoublyLink[int]()
@@ -37,12 +41,12 @@ func TestDoublyLink_InsertAtTail(t *testing.T) {
}
func TestDoublyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_InsertAt")
link := NewDoublyLink[int]()
link.InsertAt(1, 1) //do nothing
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
@@ -55,6 +59,8 @@ func TestDoublyLink_InsertAt(t *testing.T) {
}
func TestDoublyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
link := NewDoublyLink[int]()
@@ -74,6 +80,8 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
}
func TestDoublyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
link := NewDoublyLink[int]()
@@ -93,6 +101,8 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
}
func TestDoublyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
link := NewDoublyLink[int]()
@@ -116,6 +126,8 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
}
func TestDoublyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Reverse")
link := NewDoublyLink[int]()
@@ -130,6 +142,8 @@ func TestDoublyLink_Reverse(t *testing.T) {
}
func TestDoublyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_GetMiddleNode")
link := NewDoublyLink[int]()
@@ -149,10 +163,11 @@ func TestDoublyLink_GetMiddleNode(t *testing.T) {
}
func TestDoublyLink_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDoublyLink_Clear")
link := NewDoublyLink[int]()
assert.Equal(true, link.IsEmpty())
assert.Equal(0, link.Size())

View File

@@ -7,6 +7,8 @@ import (
)
func TestSinglyLink_InsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtFirst")
link := NewSinglyLink[int]()
@@ -22,6 +24,8 @@ func TestSinglyLink_InsertAtFirst(t *testing.T) {
}
func TestSinglyLink_InsertAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAtTail")
link := NewSinglyLink[int]()
@@ -37,6 +41,8 @@ func TestSinglyLink_InsertAtTail(t *testing.T) {
}
func TestSinglyLink_InsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_InsertAt")
link := NewSinglyLink[int]()
@@ -57,6 +63,8 @@ func TestSinglyLink_InsertAt(t *testing.T) {
}
func TestSinglyLink_DeleteAtHead(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
@@ -78,10 +86,11 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
}
func TestSinglyLink_DeleteAtTail(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
@@ -96,10 +105,11 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
}
func TestSinglyLink_DeleteValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteValue")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(2)
@@ -114,10 +124,11 @@ func TestSinglyLink_DeleteValue(t *testing.T) {
}
func TestSinglyLink_DeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
link.InsertAtTail(1)
link.InsertAtTail(2)
link.InsertAtTail(3)
@@ -136,6 +147,8 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
}
func TestSinglyLink_Reverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_Reverse")
link := NewSinglyLink[int]()
@@ -149,6 +162,8 @@ func TestSinglyLink_Reverse(t *testing.T) {
}
func TestSinglyLink_GetMiddleNode(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSinglyLink_GetMiddleNode")
link := NewSinglyLink[int]()
@@ -163,6 +178,7 @@ func TestSinglyLink_GetMiddleNode(t *testing.T) {
link.InsertAtTail(5)
link.InsertAtTail(6)
link.InsertAtTail(7)
middle2 := link.GetMiddleNode()
assert.Equal(4, middle2.Value)
}

View File

@@ -0,0 +1,350 @@
package datastructure
import (
"reflect"
"sort"
"sync"
)
type CopyOnWriteList[T any] struct {
data []T
lock sync.Locker
}
// NewCopyOnWriteList Creates an empty list.
func NewCopyOnWriteList[T any](data []T) *CopyOnWriteList[T] {
return &CopyOnWriteList[T]{data: data, lock: &sync.RWMutex{}}
}
func (c *CopyOnWriteList[T]) getList() []T {
return c.data
}
func (c *CopyOnWriteList[T]) setList(data []T) {
c.data = data
}
// Size returns the number of elements in this list.
func (c *CopyOnWriteList[T]) Size() int {
return len(c.getList())
}
// IsEmpty returns true if this list contains no elements.
func (c *CopyOnWriteList[T]) IsEmpty() bool {
return c.Size() == 0
}
// Contain returns true if this list contains the specified element.
func (c *CopyOnWriteList[T]) Contain(e T) bool {
list := c.getList()
return indexOf(e, list, 0, c.Size()) >= 0
}
// ValueOf returns the index of the first occurrence of the specified element in this list, or null if this list does not contain the element.
func (c *CopyOnWriteList[T]) ValueOf(index int) (*T, bool) {
list := c.getList()
if index < 0 || index >= len(c.data) {
return nil, false
}
return get(list, index), true
}
// IndexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
func (c *CopyOnWriteList[T]) IndexOf(e T) int {
list := c.getList()
return indexOf(e, list, 0, c.Size())
}
// indexOf returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
// start the start position of the search (inclusive)
// end the end position of the search (exclusive)
func indexOf[T any](o T, e []T, start int, end int) int {
if start >= end {
return -1
}
for i := start; i < end; i++ {
if reflect.DeepEqual(e[i], o) {
return i
}
}
return -1
}
// LastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int {
list := c.getList()
return lastIndexOf(e, list, 0, c.Size())
}
// lastIndexOf returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
// start the start position of the search (inclusive)
// end the end position of the search (exclusive)
func lastIndexOf[T any](o T, e []T, start int, end int) int {
if start >= end {
return -1
}
for i := end - 1; i >= start; i-- {
if reflect.DeepEqual(e[i], o) {
return i
}
}
return -1
}
// get returns the element at the specified position in this list.
func get[T any](o []T, index int) *T {
return &o[index]
}
// Get returns the element at the specified position in this list.
func (c *CopyOnWriteList[T]) Get(index int) *T {
list := c.getList()
if index < 0 || index >= len(list) {
return nil
}
return get(list, index)
}
func (c *CopyOnWriteList[T]) set(index int, e T) (oldValue *T) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
oldValue = get(list, index)
if reflect.DeepEqual(oldValue, e) {
c.setList(list)
} else {
newList := make([]T, len(list))
copy(newList, list)
newList[index] = e
c.setList(newList)
}
return
}
// Set replaces the element at the specified position in this list with the specified element.
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool) {
list := c.getList()
if index < 0 || index >= len(list) {
return oldValue, false
}
return c.set(index, e), true
}
// Add appends the specified element to the end of this list.
func (c *CopyOnWriteList[T]) Add(e T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
newList := make([]T, len(list)+1)
copy(newList, list)
newList[len(list)] = e
c.setList(newList)
return true
}
// AddAll appends all the elements in the specified collection to the end of this list
func (c *CopyOnWriteList[T]) AddAll(e []T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
newList := make([]T, len(list)+len(e))
copy(newList, list)
copy(newList[len(list):], e)
c.setList(newList)
return true
}
// AddByIndex inserts the specified element at the specified position in this list.
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
if index < 0 || index > length {
return false
}
var newList []T
var numMove = length - index
if numMove == 0 {
newList = make([]T, length+1)
copy(newList, list)
} else {
newList = make([]T, length+1)
copy(newList, list[:index])
copy(newList[index+1:], list[index:])
}
newList[index] = e
c.setList(newList)
return true
}
// delete removes the element at the specified position in this list.
func (c *CopyOnWriteList[T]) delete(index int) *T {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
oldValue := get(list, index)
numMove := length - index - 1
var newList []T
if numMove == 0 {
newList = make([]T, length-1)
copy(newList, list[:index])
} else {
newList = make([]T, length-1)
copy(newList, list[:index])
copy(newList[index:], list[index+1:])
}
c.setList(newList)
return oldValue
}
// DeleteAt removes the element at the specified position in this list.
func (c *CopyOnWriteList[T]) DeleteAt(index int) (*T, bool) {
list := c.getList()
if index < 0 || index >= len(list) {
return nil, false
}
return c.delete(index), true
}
// DeleteBy removes the first occurrence of the specified element from this list, if it is present.
func (c *CopyOnWriteList[T]) DeleteBy(o T) (*T, bool) {
list := c.getList()
index := indexOf(o, list, 0, len(list))
if index == -1 {
return nil, false
}
return c.delete(index), true
}
// DeleteRange removes from this list all the elements whose index is between fromIndex, inclusive, and toIndex, exclusive.
// left close and right open
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
if start < 0 || end > length || start > end {
return
}
var newList []T
numMove := length - end
if numMove == 0 {
newList = make([]T, length-(end-start))
copy(newList, list[:start])
} else {
newList = make([]T, length-(end-start))
copy(newList, list[:start])
copy(newList[start:], list[end:])
}
c.setList(newList)
}
// DeleteIf removes all the elements of this collection that satisfy the given predicate.
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
length := len(list)
var newList []T
for i := 0; i < length; i++ {
if !f(list[i]) {
newList = append(newList, list[i])
}
}
c.setList(newList)
}
// Equal returns true if the specified object is equal to this list.
func (c *CopyOnWriteList[T]) Equal(other *[]T) bool {
if other == nil {
return false
}
if c.Size() != len(*other) {
return false
}
list := c.getList()
otherList := NewCopyOnWriteList(*other).getList()
for i := 0; i < len(list); i++ {
if !reflect.DeepEqual(list[i], otherList[i]) {
return false
}
}
return true
}
// Clear removes all the elements from this list.
func (c *CopyOnWriteList[T]) Clear() {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
list = make([]T, 0)
c.setList(list)
}
// Merge a tow list to one, change the list
func (c *CopyOnWriteList[T]) Merge(other []T) {
lock := c.lock
lock.Lock()
defer lock.Unlock()
list := c.getList()
list = append(list, other...)
c.setList(list)
}
// ForEach performs the given action for each element of the Iterable until all elements have been processed
// or the action throws an exception.
func (c *CopyOnWriteList[T]) ForEach(f func(T)) {
list := c.getList()
for i := 0; i < len(list); i++ {
f(list[i])
}
}
// Sort sorts this list according to the order induced by the specified Comparator.
func (c *CopyOnWriteList[T]) Sort(compare func(o1 T, o2 T) bool) {
lock := c.lock
lock.Lock()
list := c.getList()
sort.Slice(list, func(i, j int) bool {
return compare(list[i], list[j])
})
c.setList(list)
}
func (c *CopyOnWriteList[T]) SubList(start int, end int) (newList []T) {
lock := c.lock
lock.Lock()
list := c.getList()
length := len(list)
defer lock.Unlock()
if start < 0 || end > length || start > end {
return []T{}
}
newList = make([]T, end-start)
copy(newList, list[start:end])
c.setList(newList)
return
}

View File

@@ -0,0 +1,235 @@
package datastructure
import (
"github.com/duke-git/lancet/v2/internal"
"testing"
)
func TestCopyOnWriteList_ValueOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
of, ok := list.ValueOf(3)
assert.Equal(4, *of)
assert.Equal(true, ok)
_, ok = list.ValueOf(6)
assert.Equal(false, ok)
}
func TestCopyOnWriteList_Contain(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Contains")
assert.Equal(true, list.Contain(3))
}
func TestCopyOnWriteList_IsEmpty(t *testing.T) {
list := NewCopyOnWriteList([]int{})
assert := internal.NewAssert(t, "CopyOnWriteList_IsEmpty")
assert.Equal(true, list.IsEmpty())
}
func TestCopyOnWriteList_Size(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_size")
assert.Equal(5, list.Size())
}
func TestCopyOnWriteList_GetList(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_GetList")
assert.Equal([]int{1, 2, 3, 4, 5}, list.getList())
}
func TestCopyOnWriteList_Get(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Get")
i := list.Get(2)
assert.Equal(3, *i)
}
func TestCopyOnWriteList_Set(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Set")
list.Set(2, 6)
assert.Equal(6, list.getList()[2])
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.Set(0, 6)
assert.Equal(6, list.getList()[0])
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.Set(0, 1)
assert.Equal(1, list.getList()[0])
}
func TestCopyOnWriteList_Add(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_Add")
list.Add(6)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
}
func TestCopyOnWriteList_AddAll(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_AddAll")
list.AddAll([]int{6, 7, 8})
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8}, list.getList())
}
func TestCopyOnWriteList_AddByIndex(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_AddByIndex")
list.AddByIndex(2, 6)
assert.Equal([]int{1, 2, 6, 3, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.AddByIndex(0, 6)
assert.Equal([]int{6, 1, 2, 3, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.AddByIndex(5, 6)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, list.getList())
}
func TestCopyOnWriteList_DeleteAt2(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByIndex")
list.DeleteAt(2)
assert.Equal([]int{1, 2, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.DeleteAt(4)
assert.Equal([]int{1, 2, 3, 4}, list.getList())
}
func TestCopyOnWriteList_RemoveByValue(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveByValue")
list.DeleteBy(3)
assert.Equal([]int{1, 2, 4, 5}, list.getList())
}
func TestCopyOnWriteList_DeleteRange(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
assert := internal.NewAssert(t, "CopyOnWriteList_RemoveRange")
list.DeleteRange(1, 3)
assert.Equal([]int{1, 4, 5}, list.getList())
list = NewCopyOnWriteList([]int{1, 2, 3, 4, 5})
list.DeleteRange(0, 5)
assert.Equal([]int{}, list.getList())
}
func TestCopyOnWriteList_LastIndexOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_LastIndexOf")
assert.Equal(5, list.LastIndexOf(3))
}
func TestCopyOnWriteList_DeleteAt(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteAt")
list.DeleteAt(2)
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
}
func TestCopyOnWriteList_DeleteBy(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteBy")
list.DeleteBy(3)
assert.Equal([]int{1, 2, 4, 5, 3}, list.getList())
}
func TestCopyOnWriteList_DeleteIf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_DeleteIf")
list.DeleteIf(func(i int) bool {
return i%2 == 0
})
assert.Equal([]int{1, 3, 5, 3}, list.getList())
}
func TestCopyOnWriteList_Equal(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_Equal")
assert.Equal(true, list.Equal(&[]int{1, 2, 3, 4, 5, 3, 6}))
}
func TestCopyOnWriteList_ForEach(t *testing.T) {
testList := make([]int, 0)
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_ForEach")
list.ForEach(func(i int) {
testList = append(testList, i)
})
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6}, testList)
list.ForEach(func(i int) {
list.Add(i)
})
assert.Equal([]int{1, 2, 3, 4, 5, 3, 6, 1, 2, 3, 4, 5, 3, 6}, list.getList())
}
func TestCopyOnWriteList_Clear(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 2, 3, 4, 5, 3, 6})
assert := internal.NewAssert(t, "CopyOnWriteList_Clear")
list.Clear()
assert.Equal([]int{}, list.getList())
}
func TestCopyOnWriteList_Merge(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9})
assert := internal.NewAssert(t, "CopyOnWriteList_Merge")
list.Merge([]int{2, 4, 6, 8, 10})
assert.Equal([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10}, list.getList())
}
func TestCopyOnWriteList_Sort(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_Sort")
list.Sort(func(i, j int) bool {
return i < j
})
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, list.getList())
}
func TestCopyOnWriteList_IndexOf(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_IndexOf")
assert.Equal(0, list.IndexOf(1))
assert.Equal(9, list.IndexOf(10))
assert.Equal(-1, list.IndexOf(11))
}
func TestCopyOnWriteList_SubList(t *testing.T) {
list := NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert := internal.NewAssert(t, "CopyOnWriteList_SubList")
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList := list.SubList(1, 3)
assert.Equal([]int{3, 5}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList = list.SubList(1, 1)
assert.Equal([]int{}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
assert.Equal(10, list.Size())
subList = list.SubList(1, 10)
assert.Equal([]int{3, 5, 7, 9, 2, 4, 6, 8, 10}, subList)
list = NewCopyOnWriteList([]int{1, 3, 5, 7, 9, 2, 4, 6, 8, 10})
subList = list.SubList(11, 1)
assert.Equal([]int{}, subList)
}

View File

@@ -271,7 +271,7 @@ func (l *List[T]) Reverse() {
}
}
// Unique remove duplicate items in list.
// Unique delete duplicate items in list.
func (l *List[T]) Unique() {
data := l.data
size := len(data)
@@ -294,7 +294,7 @@ func (l *List[T]) Unique() {
l.data = uniqueData
}
// Union creates a new list contain all element in list l and other, remove duplicate element.
// Union creates a new list contain all element in list l and other, delete duplicate element.
func (l *List[T]) Union(other *List[T]) *List[T] {
result := NewList([]T{})

View File

@@ -7,6 +7,8 @@ import (
)
func TestListData(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestListData")
list := NewList([]int{1, 2, 3})
@@ -14,6 +16,8 @@ func TestListData(t *testing.T) {
}
func TestValueOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestValueOf")
list := NewList([]int{1, 2, 3})
@@ -26,6 +30,8 @@ func TestValueOf(t *testing.T) {
}
func TestIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
@@ -37,6 +43,8 @@ func TestIndexOf(t *testing.T) {
}
func TestIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
@@ -48,6 +56,8 @@ func TestIndexOfFunc(t *testing.T) {
}
func TestLastIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
@@ -65,6 +75,8 @@ func TestLastIndexOf(t *testing.T) {
}
func TestLastIndexOfFunc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
@@ -82,6 +94,8 @@ func TestLastIndexOfFunc(t *testing.T) {
}
func TestContain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContain")
list := NewList([]int{1, 2, 3})
@@ -90,6 +104,8 @@ func TestContain(t *testing.T) {
}
func TestPush(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPush")
list := NewList([]int{1, 2, 3})
@@ -99,6 +115,8 @@ func TestPush(t *testing.T) {
}
func TestInsertAtFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtFirst")
list := NewList([]int{1, 2, 3})
@@ -108,6 +126,8 @@ func TestInsertAtFirst(t *testing.T) {
}
func TestInsertAtLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAtLast")
list := NewList([]int{1, 2, 3})
@@ -117,6 +137,8 @@ func TestInsertAtLast(t *testing.T) {
}
func TestInsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAt")
list := NewList([]int{1, 2, 3})
@@ -135,6 +157,8 @@ func TestInsertAt(t *testing.T) {
}
func TestPopFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopFirst")
list := NewList([]int{1, 2, 3})
@@ -150,6 +174,8 @@ func TestPopFirst(t *testing.T) {
}
func TestPopLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPopLast")
list := NewList([]int{1, 2, 3})
@@ -165,6 +191,8 @@ func TestPopLast(t *testing.T) {
}
func TestDeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt")
list := NewList([]int{1, 2, 3, 4})
@@ -183,6 +211,8 @@ func TestDeleteAt(t *testing.T) {
}
func TestUpdateAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpdateAt")
list := NewList([]int{1, 2, 3, 4})
@@ -201,6 +231,8 @@ func TestUpdateAt(t *testing.T) {
}
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
list1 := NewList([]int{1, 2, 3, 4})
@@ -212,6 +244,8 @@ func TestEqual(t *testing.T) {
}
func TestIsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsEmpty")
list1 := NewList([]int{1, 2, 3, 4})
@@ -222,6 +256,8 @@ func TestIsEmpty(t *testing.T) {
}
func TestIsClear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsClear")
list1 := NewList([]int{1, 2, 3, 4})
@@ -232,6 +268,8 @@ func TestIsClear(t *testing.T) {
}
func TestClone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestClone")
list1 := NewList([]int{1, 2, 3, 4})
@@ -241,6 +279,8 @@ func TestClone(t *testing.T) {
}
func TestMerge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMerge")
list1 := NewList([]int{1, 2, 3, 4})
@@ -252,6 +292,8 @@ func TestMerge(t *testing.T) {
}
func TestSize(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSize")
list := NewList([]int{1, 2, 3, 4})
@@ -262,6 +304,8 @@ func TestSize(t *testing.T) {
}
func TestCap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCap")
data := make([]int, 0, 100)
@@ -274,6 +318,8 @@ func TestCap(t *testing.T) {
}
func TestSwap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSwap")
list := NewList([]int{1, 2, 3, 4})
@@ -285,6 +331,8 @@ func TestSwap(t *testing.T) {
}
func TestReverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReverse")
list := NewList([]int{1, 2, 3, 4})
@@ -296,6 +344,8 @@ func TestReverse(t *testing.T) {
}
func TestUnique(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnique")
list := NewList([]int{1, 2, 2, 3, 4})
@@ -307,6 +357,8 @@ func TestUnique(t *testing.T) {
}
func TestUnion(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnion")
list1 := NewList([]int{1, 2, 3, 4})
@@ -318,6 +370,8 @@ func TestUnion(t *testing.T) {
}
func TestIntersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntersection")
list1 := NewList([]int{1, 2, 3, 4})
@@ -329,6 +383,8 @@ func TestIntersection(t *testing.T) {
}
func TestDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifference")
list1 := NewList([]int{1, 2, 3})
@@ -340,6 +396,8 @@ func TestDifference(t *testing.T) {
}
func TestSymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSymmetricDifference")
list1 := NewList([]int{1, 2, 3})
@@ -351,6 +409,8 @@ func TestSymmetricDifference(t *testing.T) {
}
func TestSubSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSubSlice")
list := NewList([]int{1, 2, 3, 4, 5, 8})
@@ -367,6 +427,8 @@ func BenchmarkSubSlice(b *testing.B) {
}
func TestDeleteIf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteIf")
list := NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
@@ -381,10 +443,11 @@ func TestDeleteIf(t *testing.T) {
}
func TestForEach(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
list := NewList([]int{1, 2, 3, 4})
rs := make([]int, 0)
list.ForEach(func(i int) {
rs = append(rs, i)
@@ -394,6 +457,8 @@ func TestForEach(t *testing.T) {
}
func TestRetainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRetainAll")
list := NewList([]int{1, 2, 3, 4})
@@ -414,6 +479,8 @@ func TestRetainAll(t *testing.T) {
}
func TestDeleteAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAll")
list := NewList([]int{1, 2, 3, 4})
@@ -433,10 +500,11 @@ func TestDeleteAll(t *testing.T) {
}
func TestIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIterator")
list := NewList([]int{1, 2, 3, 4})
iterator := list.Iterator()
rs := make([]int, 0)
@@ -449,14 +517,15 @@ func TestIterator(t *testing.T) {
}
func TestListToMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "ListToMap")
list := NewList([]int{1, 2, 3, 4})
result := ListToMap(list, func(n int) (int, bool) {
return n, n > 1
})
expected := map[int]bool{1: false, 2: true, 3: true, 4: true}
expected := map[int]bool{1: false, 2: true, 3: true, 4: true}
assert.Equal(expected, result)
}

View File

@@ -7,6 +7,8 @@ import (
)
func TestArrayQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Enqueue")
queue := NewArrayQueue[int](5)
@@ -14,15 +16,16 @@ func TestArrayQueue_Enqueue(t *testing.T) {
queue.Enqueue(2)
queue.Enqueue(3)
expected := []int{1, 2, 3}
data := queue.Data()
size := queue.Size()
assert.Equal(expected, data)
assert.Equal([]int{1, 2, 3}, data)
assert.Equal(3, size)
}
func TestArrayQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Dequeue")
queue := NewArrayQueue[int](4)
@@ -38,6 +41,8 @@ func TestArrayQueue_Dequeue(t *testing.T) {
}
func TestArrayQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Front")
queue := NewArrayQueue[int](4)
@@ -52,6 +57,8 @@ func TestArrayQueue_Front(t *testing.T) {
}
func TestArrayQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Back")
queue := NewArrayQueue[int](4)
@@ -66,6 +73,8 @@ func TestArrayQueue_Back(t *testing.T) {
}
func TestArrayQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Contain")
queue := NewArrayQueue[int](4)
@@ -78,6 +87,8 @@ func TestArrayQueue_Contain(t *testing.T) {
}
func TestArrayQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_Clear")
queue := NewArrayQueue[int](4)
@@ -95,6 +106,8 @@ func TestArrayQueue_Clear(t *testing.T) {
}
func TestArrayQueue_IsFull(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayQueue_IsFull")
queue := NewArrayQueue[int](3)

View File

@@ -7,6 +7,8 @@ import (
)
func TestCircularQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
queue := NewCircularQueue[int](6)
@@ -34,6 +36,8 @@ func TestCircularQueue_Enqueue(t *testing.T) {
}
func TestCircularQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
queue := NewCircularQueue[int](4)
@@ -60,6 +64,8 @@ func TestCircularQueue_Dequeue(t *testing.T) {
}
func TestCircularQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Front")
queue := NewCircularQueue[int](6)
@@ -80,6 +86,8 @@ func TestCircularQueue_Front(t *testing.T) {
}
func TestCircularQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Back")
queue := NewCircularQueue[int](3)
@@ -103,6 +111,8 @@ func TestCircularQueue_Back(t *testing.T) {
}
func TestCircularQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
queue := NewCircularQueue[int](2)
@@ -114,6 +124,8 @@ func TestCircularQueue_Contain(t *testing.T) {
}
func TestCircularQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Clear")
queue := NewCircularQueue[int](3)
@@ -132,6 +144,8 @@ func TestCircularQueue_Clear(t *testing.T) {
}
func TestCircularQueue_Data(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCircularQueue_Data")
queue := NewCircularQueue[int](3)

View File

@@ -7,6 +7,8 @@ import (
)
func TestLinkedQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Enqueue")
queue := NewLinkedQueue[int]()
@@ -19,6 +21,8 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
}
func TestLinkedQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue")
queue := NewLinkedQueue[int]()
@@ -35,6 +39,8 @@ func TestLinkedQueue_Dequeue(t *testing.T) {
}
func TestLinkedQueue_Front(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Front")
queue := NewLinkedQueue[int]()
@@ -51,6 +57,8 @@ func TestLinkedQueue_Front(t *testing.T) {
}
func TestLinkedQueue_Back(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
@@ -67,6 +75,8 @@ func TestLinkedQueue_Back(t *testing.T) {
}
func TestLinkedQueue_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Back")
queue := NewLinkedQueue[int]()
@@ -82,10 +92,11 @@ func TestLinkedQueue_Clear(t *testing.T) {
}
func TestLinkedQueue_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedQueue_Contain")
queue := NewLinkedQueue[int]()
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)

View File

@@ -20,6 +20,8 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestPriorityQueue_Enqueue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
comparator := &intComparator{}
@@ -45,6 +47,8 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
}
func TestPriorityQueue_Dequeue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
comparator := &intComparator{}

View File

@@ -7,6 +7,8 @@ import (
)
func TestSet_NewSetFromSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_NewSetFromSlice")
s1 := NewSetFromSlice([]int{1, 2, 2, 3})
@@ -20,17 +22,21 @@ func TestSet_NewSetFromSlice(t *testing.T) {
}
func TestSet_Add(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Add")
set := NewSet[int]()
set.Add(1, 2, 3)
expected := NewSet(1, 2, 3)
cmpSet := NewSet(1, 2, 3)
assert.Equal(true, set.Equal(expected))
assert.Equal(true, set.Equal(cmpSet))
}
func TestSet_AddIfNotExist(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExist")
set := NewSet[int]()
@@ -42,6 +48,8 @@ func TestSet_AddIfNotExist(t *testing.T) {
}
func TestSet_AddIfNotExistBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_AddIfNotExistBy")
set := NewSet[int]()
@@ -63,6 +71,8 @@ func TestSet_AddIfNotExistBy(t *testing.T) {
}
func TestSet_Contain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Contain")
set := NewSet[int]()
@@ -73,6 +83,8 @@ func TestSet_Contain(t *testing.T) {
}
func TestSet_ContainAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_ContainAll")
set1 := NewSet(1, 2, 3)
@@ -84,6 +96,8 @@ func TestSet_ContainAll(t *testing.T) {
}
func TestSet_Clone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Clone")
set1 := NewSet(1, 2, 3)
@@ -94,18 +108,20 @@ func TestSet_Clone(t *testing.T) {
}
func TestSet_Delete(t *testing.T) {
t.Parallel()
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))
assert.Equal(true, set.Equal(NewSet(1, 2)))
}
func TestSet_Equal(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Equal")
set1 := NewSet(1, 2, 3)
@@ -117,6 +133,8 @@ func TestSet_Equal(t *testing.T) {
}
func TestSet_Iterate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Iterate")
set := NewSet(1, 2, 3)
@@ -129,6 +147,8 @@ func TestSet_Iterate(t *testing.T) {
}
func TestSet_IsEmpty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_IsEmpty")
set := NewSet[int]()
@@ -136,6 +156,8 @@ func TestSet_IsEmpty(t *testing.T) {
}
func TestSet_Size(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Size")
set := NewSet(1, 2, 3)
@@ -143,6 +165,8 @@ func TestSet_Size(t *testing.T) {
}
func TestSet_Values(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Values")
set := NewSet(1, 2, 3)
@@ -152,28 +176,33 @@ func TestSet_Values(t *testing.T) {
}
func TestSet_Union(t *testing.T) {
t.Parallel()
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)
assert.Equal(NewSet(1, 2, 3, 4, 5), unionSet)
}
func TestSet_Intersection(t *testing.T) {
t.Parallel()
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)
assert.Equal(NewSet(2, 3), intersectionSet)
}
func TestSet_SymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_SymmetricDifference")
set1 := NewSet(1, 2, 3)
@@ -183,6 +212,8 @@ func TestSet_SymmetricDifference(t *testing.T) {
}
func TestSet_Minus(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSet_Minus")
set1 := NewSet(1, 2, 3)

View File

@@ -7,6 +7,8 @@ import (
)
func TestArrayStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Push")
stack := NewArrayStack[int]()
@@ -14,15 +16,16 @@ func TestArrayStack_Push(t *testing.T) {
stack.Push(2)
stack.Push(3)
expected := []int{3, 2, 1}
values := stack.Data()
length := stack.Size()
assert.Equal(expected, values)
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, length)
}
func TestArrayStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Pop")
stack := NewArrayStack[int]()
@@ -37,11 +40,12 @@ func TestArrayStack_Pop(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{2, 1}, stack.Data())
}
func TestArrayStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Peak")
stack := NewArrayStack[int]()
@@ -56,11 +60,12 @@ func TestArrayStack_Peak(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestArrayStack_Clear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestArrayStack_Clear")
stack := NewArrayStack[int]()

View File

@@ -7,6 +7,8 @@ import (
)
func TestLinkedStack_Push(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Push")
stack := NewLinkedStack[int]()
@@ -14,15 +16,16 @@ func TestLinkedStack_Push(t *testing.T) {
stack.Push(2)
stack.Push(3)
expected := []int{3, 2, 1}
values := stack.Data()
size := stack.Size()
assert.Equal(expected, values)
assert.Equal([]int{3, 2, 1}, values)
assert.Equal(3, size)
}
func TestLinkedStack_Pop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Pop")
stack := NewLinkedStack[int]()
@@ -37,12 +40,13 @@ func TestLinkedStack_Pop(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{2, 1}
stack.Print()
assert.Equal(expected, stack.Data())
assert.Equal([]int{2, 1}, stack.Data())
}
func TestLinkedStack_Peak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Peak")
stack := NewLinkedStack[int]()
@@ -57,11 +61,12 @@ func TestLinkedStack_Peak(t *testing.T) {
assert.IsNil(err)
assert.Equal(3, *topItem)
expected := []int{3, 2, 1}
assert.Equal(expected, stack.Data())
assert.Equal([]int{3, 2, 1}, stack.Data())
}
func TestLinkedStack_Empty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLinkedStack_Empty")
stack := NewLinkedStack[int]()

View File

@@ -20,16 +20,9 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestBSTree_Insert(t *testing.T) {
bstree := NewBSTree(6, &intComparator{})
bstree.Insert(7)
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PreOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -44,6 +37,8 @@ func TestBSTree_PreOrderTraverse(t *testing.T) {
}
func TestBSTree_PostOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_PostOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -58,6 +53,8 @@ func TestBSTree_PostOrderTraverse(t *testing.T) {
}
func TestBSTree_InOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_InOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -72,6 +69,8 @@ func TestBSTree_InOrderTraverse(t *testing.T) {
}
func TestBSTree_LevelOrderTraverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_LevelOrderTraverse")
bstree := NewBSTree(6, &intComparator{})
@@ -86,6 +85,8 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
}
func TestBSTree_Delete(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Delete")
bstree := NewBSTree(6, &intComparator{})
@@ -108,6 +109,8 @@ func TestBSTree_Delete(t *testing.T) {
}
func TestBSTree_Depth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_Depth")
bstree := NewBSTree(6, &intComparator{})
@@ -121,6 +124,8 @@ func TestBSTree_Depth(t *testing.T) {
}
func TestBSTree_IsSubTree(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBSTree_IsSubTree")
superTree := NewBSTree(8, &intComparator{})

View File

@@ -7,6 +7,8 @@ import (
)
func TestToUnix(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToUnix")
tm1 := NewUnixNow()
@@ -17,6 +19,8 @@ func TestToUnix(t *testing.T) {
}
func TestToFormat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormat")
tm, err := NewFormat("2022-03-18 17:04:05")
@@ -25,18 +29,21 @@ func TestToFormat(t *testing.T) {
}
func TestToFormatForTpl(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToFormatForTpl")
_, err := NewFormat("2022/03/18 17:04:05")
assert.IsNotNil(err)
tm, err := NewFormat("2022-03-18 17:04:05")
// assert.Equal("2022/03/18 17:04:05", tm.ToFormatForTpl("2006/01/02 15:04:05"))
t.Log("TestToFormatForTpl", tm.ToFormatForTpl("2006/01/02 15:04:05"))
assert.IsNil(err)
}
func TestToIso8601(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToIso8601")
_, err := NewISO8601("2022-03-18 17:04:05")
@@ -44,6 +51,5 @@ func TestToIso8601(t *testing.T) {
tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
t.Log("TestToIso8601", tm.ToIso8601())
// assert.Equal("2006-01-02T23:04:05+08:00", tm.ToIso8601())
assert.IsNil(err)
}

View File

@@ -3,7 +3,7 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
// 1. `format` param in FormatTimeToStr function should be as flow (case no sensitive):
// "yyyy-mm-dd hh:mm:ss"
// "yyyy-mm-dd hh:mm"
// "yyyy-mm-dd hh"
@@ -18,14 +18,19 @@
// "yyyy/mm"
// "mm/dd"
// "dd/mm/yy hh:mm:ss"
// "yyyymmdd"
// "mmddyy"
// "yyyy"
// "yy"
// "mm"
// "hh:mm:ss"
// "hh:mm"
// "mm:ss"
package datetime
import (
"fmt"
"strings"
"time"
)
@@ -47,9 +52,13 @@ func init() {
"yyyy/mm": "2006/01",
"mm/dd": "01/02",
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
"yyyymmdd": "20060102",
"mmddyy": "010206",
"yyyy": "2006",
"yy": "06",
"mm": "01",
"hh:mm:ss": "15:04:05",
"hh:mm": "15:04",
"mm:ss": "04:05",
}
}
@@ -96,6 +105,18 @@ func GetNowDateTime() string {
return time.Now().Format("2006-01-02 15:04:05")
}
// GetTodayStartTime return the start time of today, format: yyyy-mm-dd 00:00:00.
// Play: https://go.dev/play/p/84siyYF7t99
func GetTodayStartTime() string {
return time.Now().Format("2006-01-02") + " 00:00:00"
}
// GetTodayEndTime return the end time of today, format: yyyy-mm-dd 23:59:59.
// Play: https://go.dev/play/p/jjrLnfoqgn3
func GetTodayEndTime() string {
return time.Now().Format("2006-01-02") + " 23:59:59"
}
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
// Play: https://go.dev/play/p/QmL2oIaGE3q
func GetZeroHourTimestamp() int64 {
@@ -112,19 +133,40 @@ func GetNightTimestamp() int64 {
// FormatTimeToStr convert time to string.
// Play: https://go.dev/play/p/_Ia7M8H_OvE
func FormatTimeToStr(t time.Time, format string) string {
return t.Format(timeFormat[format])
func FormatTimeToStr(t time.Time, format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return t.In(loc).Format(tf)
}
return t.Format(tf)
}
// FormatStrToTime convert string to time.
// Play: https://go.dev/play/p/1h9FwdU8ql4
func FormatStrToTime(str, format string) (time.Time, error) {
v, ok := timeFormat[format]
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error) {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return time.Time{}, fmt.Errorf("format %s not found", format)
return time.Time{}, fmt.Errorf("format %s not support", format)
}
return time.Parse(v, str)
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return time.Time{}, err
}
return time.ParseInLocation(tf, str, loc)
}
return time.Parse(tf, str)
}
// BeginOfMinute return beginning minute time of day.
@@ -250,6 +292,92 @@ func DayOfYear(t time.Time) int {
// IsWeekend checks if passed time is weekend or not.
// Play: https://go.dev/play/p/cupRM5aZOIY
// Deprecated Use '== Weekday' instead
func IsWeekend(t time.Time) bool {
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
}
// NowDateOrTime return current datetime with specific format and timezone.
// Play: https://go.dev/play/p/EZ-begEjtT0
func NowDateOrTime(format string, timezone ...string) string {
tf, ok := timeFormat[strings.ToLower(format)]
if !ok {
return ""
}
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return ""
}
return time.Now().In(loc).Format(tf)
}
return time.Now().Format(tf)
}
// Timestamp return current second timestamp.
// Play: https://go.dev/play/p/iU5b7Vvjx6x
func Timestamp(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.Unix()
}
// TimestampMilli return current mill second timestamp.
// Play: https://go.dev/play/p/4gvEusOTu1T
func TimestampMilli(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Millisecond)
}
// TimestampMicro return current micro second timestamp.
// Play: https://go.dev/play/p/2maANglKHQE
func TimestampMicro(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return int64(time.Nanosecond) * t.UnixNano() / int64(time.Microsecond)
}
// TimestampNano return current nano second timestamp.
// Play: https://go.dev/play/p/A9Oq_COrcCF
func TimestampNano(timezone ...string) int64 {
t := time.Now()
if timezone != nil && timezone[0] != "" {
loc, err := time.LoadLocation(timezone[0])
if err != nil {
return 0
}
t = t.In(loc)
}
return t.UnixNano()
}

View File

@@ -8,6 +8,8 @@ import (
)
func TestAddYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
@@ -21,6 +23,8 @@ func TestAddYear(t *testing.T) {
}
func TestBetweenSeconds(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBetweenSeconds")
today := time.Now()
@@ -35,6 +39,8 @@ func TestBetweenSeconds(t *testing.T) {
}
func TestAddDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDay")
now := time.Now()
@@ -48,6 +54,8 @@ func TestAddDay(t *testing.T) {
}
func TestAddHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddHour")
now := time.Now()
@@ -61,6 +69,8 @@ func TestAddHour(t *testing.T) {
}
func TestAddMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddMinute")
now := time.Now()
@@ -74,24 +84,48 @@ func TestAddMinute(t *testing.T) {
}
func TestGetNowDate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowDate")
expected := time.Now().Format("2006-01-02")
assert.Equal(expected, GetNowDate())
}
func TestGetNowTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowTime")
expected := time.Now().Format("15:04:05")
assert.Equal(expected, GetNowTime())
}
func TestGetNowDateTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetNowDateTime")
expected := time.Now().Format("2006-01-02 15:04:05")
assert.Equal(expected, GetNowDateTime())
}
func TestGetTodayStartTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayStartTime")
expected := time.Now().Format("2006-01-02") + " 00:00:00"
assert.Equal(expected, GetTodayStartTime())
}
func TestGetTodayEndTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetTodayEndTime")
expected := time.Now().Format("2006-01-02") + " 23:59:59"
assert.Equal(expected, GetTodayEndTime())
}
func TestFormatTimeToStr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatTimeToStr")
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
@@ -113,9 +147,14 @@ func TestFormatTimeToStr(t *testing.T) {
actual := FormatTimeToStr(datetime, cases[i])
assert.Equal(expected[i], actual)
}
ds := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(ds)
}
func TestFormatStrToTime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFormatStrToTime")
formats := []string{
@@ -127,22 +166,28 @@ func TestFormatStrToTime(t *testing.T) {
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
"yyyy/mm"}
datetimeStr := []string{
expected := []string{
"2021-01-02 16:04:08", "2021-01-02",
"02-01-21 16:04:08", "2021/01/02 16:04:08",
"2021/01"}
for i := 0; i < len(cases); i++ {
actual, err := FormatStrToTime(datetimeStr[i], cases[i])
actual, err := FormatStrToTime(expected[i], cases[i])
if err != nil {
t.Fatal(err)
}
expected, _ := time.Parse(formats[i], datetimeStr[i])
expected, _ := time.Parse(formats[i], expected[i])
assert.Equal(expected, actual)
}
estTime, err := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss", "EST")
t.Log(estTime)
assert.IsNil(err)
}
func TestBeginOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 0, 0, time.Local)
@@ -153,6 +198,8 @@ func TestBeginOfMinute(t *testing.T) {
}
func TestEndOfMinute(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMinute")
expected := time.Date(2022, 2, 15, 15, 48, 59, 999999999, time.Local)
@@ -163,6 +210,8 @@ func TestEndOfMinute(t *testing.T) {
}
func TestBeginOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfHour")
expected := time.Date(2022, 2, 15, 15, 0, 0, 0, time.Local)
@@ -173,6 +222,8 @@ func TestBeginOfHour(t *testing.T) {
}
func TestEndOfHour(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfHour")
expected := time.Date(2022, 2, 15, 15, 59, 59, 999999999, time.Local)
@@ -183,6 +234,8 @@ func TestEndOfHour(t *testing.T) {
}
func TestBeginOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfDay")
expected := time.Date(2022, 2, 15, 0, 0, 0, 0, time.Local)
@@ -193,6 +246,8 @@ func TestBeginOfDay(t *testing.T) {
}
func TestEndOfDay(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfDay")
expected := time.Date(2022, 2, 15, 23, 59, 59, 999999999, time.Local)
@@ -203,6 +258,8 @@ func TestEndOfDay(t *testing.T) {
}
func TestBeginOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfWeek")
expected := time.Date(2022, 2, 13, 0, 0, 0, 0, time.Local)
@@ -213,6 +270,8 @@ func TestBeginOfWeek(t *testing.T) {
}
func TestEndOfWeek(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfWeek")
expected := time.Date(2022, 2, 19, 23, 59, 59, 999999999, time.Local)
@@ -223,6 +282,8 @@ func TestEndOfWeek(t *testing.T) {
}
func TestBeginOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfMonth")
expected := time.Date(2022, 2, 1, 0, 0, 0, 0, time.Local)
@@ -233,6 +294,8 @@ func TestBeginOfMonth(t *testing.T) {
}
func TestEndOfMonth(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfMonth")
expected := time.Date(2022, 2, 28, 23, 59, 59, 999999999, time.Local)
@@ -243,6 +306,8 @@ func TestEndOfMonth(t *testing.T) {
}
func TestBeginOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeginOfYear")
expected := time.Date(2022, 1, 1, 0, 0, 0, 0, time.Local)
@@ -253,6 +318,8 @@ func TestBeginOfYear(t *testing.T) {
}
func TestEndOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
expected := time.Date(2022, 12, 31, 23, 59, 59, 999999999, time.Local)
@@ -263,6 +330,8 @@ func TestEndOfYear(t *testing.T) {
}
func TestIsLeapYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEndOfYear")
result1 := IsLeapYear(2000)
@@ -273,6 +342,8 @@ func TestIsLeapYear(t *testing.T) {
}
func TestDayOfYear(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDayOfYear")
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
result1 := DayOfYear(date1)
@@ -288,7 +359,10 @@ func TestDayOfYear(t *testing.T) {
}
func TestIsWeekend(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsWeekend")
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
result := IsWeekend(date)
assert.Equal(true, result)
@@ -300,5 +374,39 @@ func TestIsWeekend(t *testing.T) {
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)
}

View File

@@ -30,6 +30,7 @@ import (
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
- [InDelta](#InDelta)
<div STYLE="page-break-after: always;"></div>
@@ -324,3 +325,50 @@ func main() {
// false
}
```
### <span id="InDelta">InDelta</span>
<p>Checks if two values are equal or not within a delta.</p>
<b>Signature:</b>
```go
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
```

View File

@@ -30,6 +30,8 @@ import (
- [GreaterThan](#GreaterThan)
- [LessOrEqual](#LessOrEqual)
- [GreaterOrEqual](#GreaterOrEqual)
- [InDelta](#InDelta)
<div STYLE="page-break-after: always;"></div>
@@ -324,3 +326,50 @@ func main() {
// false
}
```
### <span id="InDelta">InDelta</span>
<p>检查增量内两个值是否相等。</p>
<b>函数签名:</b>
```go
func InDelta[T constraints.Integer | constraints.Float](left, right T, delta float64) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/compare"
)
func main() {
result1 := InDelta(1, 1, 0)
result2 := InDelta(1, 2, 0)
result3 := InDelta(2.0/3.0, 0.66667, 0.001)
result4 := InDelta(2.0/3.0, 0.0, 0.001)
result5 := InDelta(float64(74.96)-float64(20.48), 54.48, 0)
result6 := InDelta(float64(74.96)-float64(20.48), 54.48, 1e-14)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// true
// false
// true
// false
// false
// true
}
```

View File

@@ -6,7 +6,7 @@ Package cryptor contains some functions for data encryption and decryption. Supp
## Source:
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/crypto.go](https://github.com/duke-git/lancet/blob/main/cryptor/crypto.go)
@@ -44,14 +44,24 @@ import (
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacMd5WithBase64](#HmacMd5WithBase64)
- [HmacSha1](#HmacSha1)
- [HmacSha1WithBase64](#HmacSha1WithBase64)
- [HmacSha256](#HmacSha256)
- [HmacSha256WithBase64](#HmacSha256WithBase64)
- [HmacSha512](#HmacSha512)
- [HmacSha512WithBase64](#HmacSha512WithBase64)
- [Md5String](#Md5String)
- [Md5StringWithBase64](#Md5StringWithBase64)
- [Md5Byte](#Md5Byte)
- [Md5ByteWithBase64](#Md5ByteWithBase64)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha1WithBase64](#Sha1WithBase64)
- [Sha256](#Sha256)
- [Sha256WithBase64](#Sha256WithBase64)
- [Sha512](#Sha512)
- [Sha512WithBase64](#Sha512WithBase64)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
@@ -729,7 +739,7 @@ func main() {
<b>Signature:</b>
```go
func HmacMd5(data, key string) string
func HmacMd5(str, key string) string
```
<b>Example:</b>
@@ -743,7 +753,7 @@ import (
)
func main() {
str := "hello"
str := "hello"
key := "12345"
hms := cryptor.HmacMd5(str, key)
@@ -753,6 +763,39 @@ func main() {
// e834306eab892d872525d4918a7a639a
}
```
### <span id="HmacMd5WithBase64">HmacMd5WithBase64</span>
<p>Get the md5 hmac hash of base64 string.</p>
<b>Signature:</b>
```go
func HmacMd5WithBase64(str, key string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacMd5WithBase64(str, key)
fmt.Println(hms)
// Output:
// 6DQwbquJLYclJdSRinpjmg==
}
```
### <span id="HmacSha1">HmacSha1</span>
<p>Get the sha1 hmac hash of string.</p>
@@ -760,7 +803,7 @@ func main() {
<b>Signature:</b>
```go
func HmacSha1(data, key string) string
func HmacSha1(str, key string) string
```
<b>Example:</b>
@@ -784,6 +827,39 @@ func main() {
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
```
### <span id="HmacSha1WithBase64">HmacSha1WithBase64</span>
<p>Return the hmac hash of string use sha1 with base64.</p>
<b>Signature:</b>
```go
func HmacSha1WithBase64(str, key string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha1WithBase64(str, key)
fmt.Println(hms)
// Output:
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
}
```
### <span id="HmacSha256">HmacSha256</span>
<p>Get the sha256 hmac hash of string</p>
@@ -791,7 +867,7 @@ func main() {
<b>Signature:</b>
```go
func HmacSha256(data, key string) string
func HmacSha256(str, key string) string
```
<b>Example:</b>
@@ -816,6 +892,38 @@ func main() {
}
```
### <span id="HmacSha256WithBase64">HmacSha256WithBase64</span>
<p>Return the hmac hash of string use sha256 with base64.</p>
<b>Signature:</b>
```go
func HmacSha256WithBase64(str, key string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha256WithBase64(str, key)
fmt.Println(hms)
// Output:
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
}
```
### <span id="HmacSha512">HmacSha512</span>
<p>Get the sha512 hmac hash of string.</p>
@@ -823,7 +931,7 @@ func main() {
<b>Signature:</b>
```go
func HmacSha512(data, key string) string
func HmacSha512(str, key string) string
```
<b>Example:</b>
@@ -848,6 +956,38 @@ func main() {
}
```
### <span id="HmacSha512WithBase64">HmacSha512WithBase64</span>
<p>Return the hmac hash of string use sha512 with base64.</p>
<b>Signature:</b>
```go
func HmacSha512WithBase64(str, key string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha512WithBase64(str, key)
fmt.Println(hms)
// Output:
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
}
```
### <span id="Md5String">Md5String</span>
@@ -880,6 +1020,93 @@ func main() {
}
```
### <span id="Md5StringWithBase64">Md5StringWithBase64</span>
<p>Return the md5 value of string with base64.</p>
<b>Signature:</b>
```go
func Md5StringWithBase64(s string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5StringWithBase64("hello")
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
```
### <span id="Md5Byte">Md5Byte</span>
<p>Return the md5 string of byte slice.</p>
<b>Signature:</b>
```go
func Md5Byte(data []byte) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5Byte([]byte{'a'})
fmt.Println(md5Str)
// Output:
// 0cc175b9c0f1b6a831c399e269772661
}
```
### <span id="Md5ByteWithBase64">Md5ByteWithBase64</span>
<p>Return the md5 string of byte slice with base64.</p>
<b>Signature:</b>
```go
func Md5ByteWithBase64(data []byte) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
```
### <span id="Md5File">Md5File</span>
<p>Get the md5 value of file.</p>
@@ -913,7 +1140,7 @@ func main() {
<b>Signature:</b>
```go
func Sha1(data string) string
func Sha1(str string) string
```
<b>Example:</b>
@@ -937,6 +1164,35 @@ func main() {
}
```
### <span id="Sha1WithBase64">Sha1WithBase64</span>
<p>Return the sha1 value (SHA-1 hash algorithm) of base64 string.</p>
<b>Signature:</b>
```go
func Sha1WithBase64(str string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha1WithBase64("hello")
fmt.Println(result)
// Output:
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
}
```
### <span id="Sha256">Sha256</span>
<p>Get the sha256 value of string.</p>
@@ -944,7 +1200,7 @@ func main() {
<b>Signature:</b>
```go
func Sha256(data string) string
func Sha256(str string) string
```
<b>Example:</b>
@@ -968,6 +1224,35 @@ func main() {
}
```
### <span id="Sha256WithBase64">Sha256WithBase64</span>
<p>Return the sha256 value (SHA256 hash algorithm) of base64 string.</p>
<b>Signature:</b>
```go
func Sha256WithBase64(str string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha256WithBase64("hello")
fmt.Println(result)
// Output:
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
}
```
### <span id="Sha512">Sha512</span>
<p>Get the sha512 value of string.</p>
@@ -975,7 +1260,7 @@ func main() {
<b>Signature:</b>
```go
func Sha512(data string) string
func Sha512(str string) string
```
<b>Example:</b>
@@ -999,6 +1284,35 @@ func main() {
}
```
### <span id="Sha512WithBase64">Sha512WithBase64</span>
<p>Get the sha512 value of string with base64.</p>
<b>Signature:</b>
```go
func Sha512WithBase64(str string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha512WithBase64("hello")
fmt.Println(result)
// Output:
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
}
```
### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>Create the rsa public and private key file in current directory.</p>

View File

@@ -6,7 +6,7 @@ cryptor加密包支持数据加密和解密获取md5hash值。支持base64
## 源码:
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/crypto.go](https://github.com/duke-git/lancet/blob/main/cryptor/crypto.go)
<div STYLE="page-break-after: always;"></div>
@@ -41,14 +41,24 @@ import (
- [DesOfbEncrypt](#DesOfbEncrypt)
- [DesOfbDecrypt](#DesOfbDecrypt)
- [HmacMd5](#HmacMd5)
- [HmacMd5WithBase64](#HmacMd5WithBase64)
- [HmacSha1](#HmacSha1)
- [HmacSha1WithBase64](#HmacSha1WithBase64)
- [HmacSha256](#HmacSha256)
- [HmacSha256WithBase64](#HmacSha256WithBase64)
- [HmacSha512](#HmacSha512)
- [HmacSha512WithBase64](#HmacSha512WithBase64)
- [Md5String](#Md5String)
- [Md5StringWithBase64](#Md5StringWithBase64)
- [Md5Byte](#Md5Byte)
- [Md5ByteWithBase64](#Md5ByteWithBase64)
- [Md5File](#Md5File)
- [Sha1](#Sha1)
- [Sha1WithBase64](#Sha1WithBase64)
- [Sha256](#Sha256)
- [Sha256WithBase64](#Sha256WithBase64)
- [Sha512](#Sha512)
- [Sha512WithBase64](#Sha512WithBase64)
- [GenerateRsaKey](#GenerateRsaKey)
- [RsaEncrypt](#RsaEncrypt)
- [RsaDecrypt](#RsaDecrypt)
@@ -728,7 +738,7 @@ func main() {
<b>函数签名:</b>
```go
func HmacMd5(data, key string) string
func HmacMd5(str, key string) string
```
<b>示例:</b>
@@ -742,7 +752,7 @@ import (
)
func main() {
str := "hello"
str := "hello"
key := "12345"
hms := cryptor.HmacMd5(str, key)
@@ -752,14 +762,46 @@ func main() {
// e834306eab892d872525d4918a7a639a
}
```
### <span id="HmacSha1">HmacSha1</span>
<p>获取字符串sha1 hmac值。</p>
### <span id="HmacMd5WithBase64">HmacMd5WithBase64</span>
<p>获取字符串md5 hmac base64字符串值。</p>
<b>函数签名:</b>
```go
func HmacSha1(data, key string) string
func HmacMd5WithBase64(str, key string) string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacMd5WithBase64(str, key)
fmt.Println(hms)
// Output:
// 6DQwbquJLYclJdSRinpjmg==
}
```
### <span id="HmacSha1">HmacSha1</span>
<p>获取字符串的sha1 hmac值。</p>
<b>函数签名:</b>
```go
func HmacSha1(str, key string) string
```
<b>示例:</b>
@@ -783,6 +825,40 @@ func main() {
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
}
```
### <span id="HmacSha1WithBase64">HmacSha1WithBase64</span>
<p>获取字符串的sha1 base64值。</p>
<b>函数签名:</b>
```go
func HmacSha1WithBase64(str, key string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha1WithBase64(str, key)
fmt.Println(hms)
// Output:
// XGqdsMzLkuNu0DI/0Jt/k23prOA=
}
```
### <span id="HmacSha256">HmacSha256</span>
<p>获取字符串sha256 hmac值。</p>
@@ -790,7 +866,7 @@ func main() {
<b>函数签名:</b>
```go
func HmacSha256(data, key string) string
func HmacSha256(str, key string) string
```
<b>示例:</b>
@@ -815,6 +891,38 @@ func main() {
}
```
### <span id="HmacSha256WithBase64">HmacSha256WithBase64</span>
<p>获取字符串sha256 hmac base64值。</p>
<b>函数签名:</b>
```go
func HmacSha256WithBase64(str, key string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha256WithBase64(str, key)
fmt.Println(hms)
// Output:
// MVu5PE6YmGK6Ccti4F1zpfN2yzbw14btqwwyDQWf3nU=
}
```
### <span id="HmacSha512">HmacSha512</span>
<p>获取字符串sha512 hmac值。</p>
@@ -822,7 +930,7 @@ func main() {
<b>函数签名:</b>
```go
func HmacSha512(data, key string) string
func HmacSha512(str, key string) string
```
<b>示例:</b>
@@ -847,6 +955,38 @@ func main() {
}
```
### <span id="HmacSha512WithBase64">HmacSha512WithBase64</span>
<p>获取字符串sha512 hmac base64值。</p>
<b>函数签名:</b>
```go
func HmacSha512WithBase64(str, key string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
str := "hello"
key := "12345"
hms := cryptor.HmacSha512WithBase64(str, key)
fmt.Println(hms)
// Output:
// 3Y8SkKndI9NU4lJtmi6c6M///dN8syCADRxsE9Lvw2Mog3ahlsVFja9T+OGqa0Wm2FYwPVwKIGS/+XhYYdSM/A==
}
```
### <span id="Md5String">Md5String</span>
@@ -855,7 +995,7 @@ func main() {
<b>函数签名:</b>
```go
func Md5String(s string) string
func Md5String(str string) string
```
<b>示例:</b>
@@ -879,6 +1019,93 @@ func main() {
}
```
### <span id="Md5StringWithBase64">Md5StringWithBase64</span>
<p>获取字符串md5 base64值。</p>
<b>函数签名:</b>
```go
func Md5StringWithBase64(s string) string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5StringWithBase64("hello")
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
```
### <span id="Md5Byte">Md5Byte</span>
<p>获取byte slice的md5值。</p>
<b>函数签名:</b>
```go
func Md5Byte(data []byte) string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5Byte([]byte{'a'})
fmt.Println(md5Str)
// Output:
// 0cc175b9c0f1b6a831c399e269772661
}
```
### <span id="Md5ByteWithBase64">Md5ByteWithBase64</span>
<p>获取byte slice的md5 base64值。</p>
<b>函数签名:</b>
```go
func Md5ByteWithBase64(data []byte) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
md5Str := cryptor.Md5ByteWithBase64([]byte("hello"))
fmt.Println(md5Str)
// Output:
// XUFAKrxLKna5cZ2REBfFkg==
}
```
### <span id="Md5File">Md5File</span>
<p>获取文件md5值。</p>
@@ -912,7 +1139,7 @@ func main() {
<b>函数签名:</b>
```go
func Sha1(data string) string
func Sha1(str string) string
```
<b>示例:</b>
@@ -936,6 +1163,35 @@ func main() {
}
```
### <span id="Sha1WithBase64">Sha1WithBase64</span>
<p>获取字符串sha1 base64值。</p>
<b>函数签名:</b>
```go
func Sha1WithBase64(str string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha1WithBase64("hello")
fmt.Println(result)
// Output:
// qvTGHdzF6KLavt4PO0gs2a6pQ00=
}
```
### <span id="Sha256">Sha256</span>
<p>获取字符串sha256值。</p>
@@ -943,7 +1199,7 @@ func main() {
<b>函数签名:</b>
```go
func Sha256(data string) string
func Sha256(str string) string
```
<b>示例:</b>
@@ -967,6 +1223,35 @@ func main() {
}
```
### <span id="Sha256WithBase64">Sha256WithBase64</span>
<p>获取字符串sha256 base64值。</p>
<b>函数签名:</b>
```go
func Sha256WithBase64(str string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha256WithBase64("hello")
fmt.Println(result)
// Output:
// LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
}
```
### <span id="Sha512">Sha512</span>
<p>获取字符串sha512值。</p>
@@ -974,7 +1259,7 @@ func main() {
<b>函数签名:</b>
```go
func Sha512(data string) string
func Sha512(str string) string
```
<b>示例:</b>
@@ -998,6 +1283,35 @@ func main() {
}
```
### <span id="Sha512WithBase64">Sha512WithBase64</span>
<p>获取字符串sha512 base64值。</p>
<b>函数签名:</b>
```go
func Sha512WithBase64(str string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
result := cryptor.Sha512WithBase64("hello")
fmt.Println(result)
// Output:
// m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==
}
```
### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>在当前目录下创建rsa私钥文件和公钥文件。</p>

View File

@@ -0,0 +1,470 @@
# CopyOnWriteList
CopyOnWriteList is a thread-safe list implementation that uses go slicing as its base. When writing, a new slice is copied and assigned to the original slice when writing is complete. When reading, the original slice is read directly.
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go](https://github.com/duke-git/lancet/blob/main /datastructure/list/copyonwritelist.go)
## 用法
```go
import (
"github.com/duke-git/lancet/datastructure/list"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewCopyOnWriteList](#NewCopyOnWriteList)
- [Size](#Size)
- [Get](#Get)
- [Set](#Set)
- [Remove](#Remove)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IsEmpty](#IsEmpty)
- [Contain](#Contain)
- [ValueOf](#ValueOf)
- [Add](#Add)
- [AddAll](#AddAll)
- [AddByIndex](#AddByIndex)
- [DeleteAt](#DeleteAt)
- [DeleteIf](#DeleteIf)
- [DeleteBy](#DeleteBy)
- [DeleteRange](#DeleteRange)
- [Equal](#Equal)
## Documentation
### NewCopyOnWriteList
Returns a CopyOnWriteList with empty slices.
```go
type CopyOnWriteList[T any] struct {
data []T
lock sync.
}
func NewCopyOnWriteList() *CopyOnWriteList
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l)
}
```
### Size
Returns the length of the CopyOnWriteList.
```go
func (l *CopyOnWriteList[T]) Size() int
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Size())
}
```
### Get
Returns the element at the specified position in the list
```go
func (c *CopyOnWriteList[T]) Get(index int) *T
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Get(2))
}
```
### Set
Replaces the element at the specified position in this list with the specified element.
```go
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool)
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Set(2, 4))
}
```
### Remove
### IndexOf
Returns the index of the value in the list, or -1 if not found.
```go
func (c *CopyOnWriteList[T]) IndexOf(e T) int
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.IndexOf(1))
}
```
### LastIndexOf
Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain that element.
```go
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,1})
fmt.Println(l.LastIndexOf(1))
}
```
### IsEmpty
Returns true if this list does not contain any elements.
```go
func (c *CopyOnWriteList[T]) IsEmpty() bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{})
fmt.Println(l.IsEmpty())
}
```
### Contain
Determines if a CopyOnWriteList contains an element.
```go
func (c *CopyOnWriteList[T]) Contain(e T) bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Contain(1))
}
```
### ValueOf
Returns a pointer to the value at the index in the list
```go
func (c *CopyOnWriteList[T]) ValueOf(index int) []T
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.ValueOf(2))
}
```
### Add
Appends the specified element to the end of the list.
```go
func (c *CopyOnWriteList[T]) Add(e T) bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.Add(4)
fmt.Println(l.getList())
}
```
### AddAll
Appends all the elements of the specified collection to the end of this list
```go
func (c *CopyOnWriteList[T]) AddAll(e []T) bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.AddAll([]int{4,5,6})
fmt.Println(l.getList())
}
```
### AddByIndex
Inserts the specified element into the list at the specified position.
```go
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.AddByIndex(2, 6)
fmt.Println(l.getList())
}
```
### DeleteAt
Removes the element at the specified position in this list.
```go
func (c *CopyOnWriteList[T]) DeleteAt(index int) (oldValue *T, ok bool)
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteAt(2)
fmt.Println(l.getList())
}
```
### DeleteIf
Removes the first occurrence of the specified element from this list (if it exists).
```go
func (c *CopyOnWriteList[T]) DeleteIf(func(T) bool) (oldValue *T, ok bool)
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteIf(func(i int) bool {
return i == 2
})
fmt.Println(l.getList())
}
```
### DeleteBy
Deletes the first occurrence of the specified element from this list (if it exists).
```go
func (c *CopyOnWriteList[T]) DeleteBy(e T) (*T bool)
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteBy(2)
fmt.Println(l.getList())
}
```
### DeleteRange
Deletes all elements from this list with indexes between fromIndex (included) and toIndex (not included).
(leftCloseRightOpen)
```go
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int)
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
list.DeleteRange(2, 5)
fmt.Println(l.getList())
}
```
### Equal
Returns true if the specified object is equal to this list
```go
func (c *CopyOnWriteList[T]) Equal(e []T) bool
```
#### Example
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
fmt.Println(l.Equal([]int{1,2,3,4,5,6,7,8,9}))
}
```

View File

@@ -0,0 +1,471 @@
# CopyOnWriteList
CopyOnWriteList 是一个线程安全的 List 实现,底层使用 go 切片。写入时,会复制一份新的切片,写入完成后,再将新的切片赋值给原来的切片。读取时,直接读取原来的切片。
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go](https://github.com/duke-git/lancet/blob/main/datastructure/list/copyonwritelist.go)
## 用法
```go
import (
"github.com/duke-git/lancet/datastructure/list"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewCopyOnWriteList](#NewCopyOnWriteList)
- [Size](#Size)
- [Get](#Get)
- [Set](#Set)
- [Remove](#Remove)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IsEmpty](#IsEmpty)
- [Contain](#Contain)
- [ValueOf](#ValueOf)
- [Add](#Add)
- [AddAll](#AddAll)
- [AddByIndex](#AddByIndex)
- [DeleteAt](#DeleteAt)
- [DeleteIf](#DeleteIf)
- [DeleteBy](#DeleteBy)
- [DeleteRange](#DeleteRange)
- [Equal](#Equal)
## 文档
### NewCopyOnWriteList
返回一个具有空切片的 CopyOnWriteList。
```go
type CopyOnWriteList[T any] struct {
data []T
lock sync.Locker
}
func NewCopyOnWriteList() *CopyOnWriteList
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l)
}
```
### Size
返回 CopyOnWriteList 的长度。
```go
func (l *CopyOnWriteList[T]) Size() int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Size())
}
```
### Get
返回列表中指定位置的元素
```go
func (c *CopyOnWriteList[T]) Get(index int) *T
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Get(2))
}
```
### Set
将此列表中指定位置的元素替换为指定元素。
```go
func (c *CopyOnWriteList[T]) Set(index int, e T) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Set(2, 4))
}
```
### Remove
### IndexOf
返回列表中值的索引,如果没有找到返回-1。
```go
func (c *CopyOnWriteList[T]) IndexOf(e T) int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.IndexOf(1))
}
```
### LastIndexOf
返回指定元素在此列表中最后出现的索引,如果此列表不包含该元素,则返回-1。
```go
func (c *CopyOnWriteList[T]) LastIndexOf(e T) int
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,1})
fmt.Println(l.LastIndexOf(1))
}
```
### IsEmpty
如果此列表不包含任何元素,则返回 true。
```go
func (c *CopyOnWriteList[T]) IsEmpty() bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{})
fmt.Println(l.IsEmpty())
}
```
### Contain
判断 CopyOnWriteList 是否包含某个元素
```go
func (c *CopyOnWriteList[T]) Contain(e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.Contain(1))
}
```
### ValueOf
返回列表中索引处的值指针
```go
func (c *CopyOnWriteList[T]) ValueOf(index int) []T
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
fmt.Println(l.ValueOf(2))
}
```
### Add
将指定的元素追加到此列表的末尾。
```go
func (c *CopyOnWriteList[T]) Add(e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.Add(4)
fmt.Println(l.getList())
}
```
### AddAll
将指定集合中的所有元素追加到此列表的末尾
```go
func (c *CopyOnWriteList[T]) AddAll(e []T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
l.AddAll([]int{4,5,6})
fmt.Println(l.getList())
}
```
### AddByIndex
将指定元素插入此列表中的指定位置。
```go
func (c *CopyOnWriteList[T]) AddByIndex(index int, e T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.AddByIndex(2, 6)
fmt.Println(l.getList())
}
```
### DeleteAt
移除此列表中指定位置的元素。
```go
func (c *CopyOnWriteList[T]) DeleteAt(index int) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteAt(2)
fmt.Println(l.getList())
}
```
### DeleteIf
从此列表中删除第一个出现的指定元素(如果该元素存在)。
```go
func (c *CopyOnWriteList[T]) DeleteIf(f func(T) bool) (oldValue *T, ok bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteIf(func(i int) bool {
return i == 2
})
fmt.Println(l.getList())
}
```
### DeleteBy
从此列表中删除第一个出现的指定元素(如果该元素存在)。
```go
func (c *CopyOnWriteList[T]) DeleteBy(e T) (*T bool)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3})
list.DeleteBy(2)
fmt.Println(l.getList())
}
```
### DeleteRange
从该列表中删除索引介于 fromIndex(包含)和 toIndex(不包含)之间的所有元素。
(左闭右开)。
```go
func (c *CopyOnWriteList[T]) DeleteRange(start int, end int)
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
list.DeleteRange(2, 5)
fmt.Println(l.getList())
}
```
### Equal
如果指定的对象等于此列表,则返回 true。
```go
func (c *CopyOnWriteList[T]) Equal(e []T) bool
```
#### 示例
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/datastructure/list"
)
func main() {
l := list.NewCopyOnWriteList([]int{1,2,3,4,5,6,7,8,9})
fmt.Println(l.Equal([]int{1,2,3,4,5,6,7,8,9}))
}
```

View File

@@ -42,6 +42,8 @@ import (
- [GetNowDate](#GetNowDate)
- [GetNowTime](#GetNowTime)
- [GetNowDateTime](#GetNowDateTime)
- [GetTodayStartTime](#GetTodayStartTime)
- [GetTodayEndTime](#GetTodayEndTime)
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
@@ -57,7 +59,12 @@ import (
- [IsLeapYear](#IsLeapYear)
- [BetweenSeconds](#BetweenSeconds)
- [DayOfYear](#DayOfYear)
- [IsWeekend](#IsWeekend)
- [IsWeekend<sup>deprecated</sup>](#IsWeekend)
- [NowDateOrTime](#NowDateOrTime)
- [Timestamp](#Timestamp)
- [TimestampMilli](#TimestampMilli)
- [TimestampMicro](#TimestampMicro)
- [TimestampNano](#TimestampNano)
<div STYLE="page-break-after: always;"></div>
@@ -65,7 +72,7 @@ import (
## Note:
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
1. In below functions, the `format` string param should be one of flows value (case no sensitive):
- yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm
@@ -76,14 +83,18 @@ import (
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyymmdd
- mmddyy
- yyyy
- yy
- mm
- hh:mm:ss
- hh:mm
- mm:ss
### <span id="AddDay">AddDay</span>
@@ -643,14 +654,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentDate := datetime.GetNowDate()
fmt.Println(currentDate)
// Output:
@@ -675,14 +683,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentTime := datetime.GetNowTime()
fmt.Println(currentTime) // 15:57:33
// Output:
@@ -707,14 +712,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
current := datetime.GetNowDateTime()
fmt.Println(current)
// Output:
@@ -722,6 +724,64 @@ func main() {
}
```
### <span id="GetTodayStartTime">GetTodayStartTime</span>
<p>Return the start time of today, format: yyyy-mm-dd 00:00:00.</p>
<b>Signature:</b>
```go
func GetTodayStartTime() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
startTime := datetime.GetTodayStartTime()
fmt.Println(startTime)
// Output:
// 2023-06-29 00:00:00
}
```
### <span id="GetTodayEndTime">GetTodayEndTime</span>
<p>Return the end time of today, format: yyyy-mm-dd 23:59:59.</p>
<b>Signature:</b>
```go
func GetTodayEndTime() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
endTime := datetime.GetTodayEndTime()
fmt.Println(endTime)
// Output:
// 2023-06-29 23:59:59
}
```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>Return timestamp of zero hour (timestamp of 00:00).</p>
@@ -739,14 +799,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime)
// Output:
@@ -771,14 +828,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime)
// Output:
@@ -793,7 +847,7 @@ func main() {
<b>Signature:</b>
```go
func FormatTimeToStr(t time.Time, format string) string
func FormatTimeToStr(t time.Time, format string, timezone ...string) string
```
<b>Example:</b>
@@ -832,7 +886,7 @@ func main() {
<b>Signature:</b>
```go
func FormatStrToTime(str, format string) (time.Time, error)
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error)
```
<b>Example:</b>
@@ -1140,7 +1194,6 @@ func main() {
}
```
### <span id="BetweenSeconds">BetweenSeconds</span>
<p>Return the number of seconds between two times.</p>
@@ -1178,7 +1231,6 @@ func main() {
}
```
### <span id="DayOfYear">DayOfYear</span>
<p>Returns which day of the year the parameter date `t` is.</p>
@@ -1220,8 +1272,7 @@ func main() {
}
```
### <span id="IsWeekend">IsWeekend</span>
### <span id="IsWeekend">IsWeekend(Deprecated, Use '== Weekday' instead)</span>
<p>Checks if passed time is weekend or not.</p>
@@ -1260,3 +1311,158 @@ func main() {
// false
}
```
### <span id="NowDateOrTime">NowDateOrTime</span>
<p>Return current datetime with specific format and timezone.</p>
<b>Signature:</b>
```go
func NowDateOrTime(format string, timezone ...string) string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 2023-07-26 15:01:30
// 2023-07-26 02:01:30
}
```
### <span id="Timestamp">Timestamp</span>
<p>Return current second timestamp.</p>
<b>Signature:</b>
```go
func Timestamp(timezone ...string) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.Timestamp()
fmt.Println(ts)
// Output:
// 1690363051
}
```
### <span id="TimestampMilli">TimestampMilli</span>
<p>Return current mill second timestamp.</p>
<b>Signature:</b>
```go
func TimestampMilli(timezone ...string) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampMilli()
fmt.Println(ts)
// Output:
// 1690363051331
}
```
### <span id="TimestampMicro">TimestampMicro</span>
<p>Return current micro second timestamp.</p>
<b>Signature:</b>
```go
func TimestampMicro(timezone ...string) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampMicro()
fmt.Println(ts)
// Output:
// 1690363051331784
}
```
### <span id="TimestampNano">TimestampNano</span>
<p>Return current nano second timestamp.</p>
<b>Signature:</b>
```go
func TimestampNano(timezone ...string) int64
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampNano()
fmt.Println(ts)
// Output:
// 1690363051331788000
}
```

View File

@@ -41,6 +41,8 @@ import (
- [GetNowDate](#GetNowDate)
- [GetNowTime](#GetNowTime)
- [GetNowDateTime](#GetNowDateTime)
- [GetTodayStartTime](#GetTodayStartTime)
- [GetTodayEndTime](#GetTodayEndTime)
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
- [GetNightTimestamp](#GetNightTimestamp)
- [FormatTimeToStr](#FormatTimeToStr)
@@ -56,8 +58,12 @@ import (
- [IsLeapYear](#IsLeapYear)
- [BetweenSeconds](#BetweenSeconds)
- [DayOfYear](#DayOfYear)
- [IsWeekend](#IsWeekend)
- [IsWeekend<sup>deprecated</sup>](#IsWeekend)
- [NowDateOrTime](#NowDateOrTime)
- [Timestamp](#Timestamp)
- [TimestampMilli](#TimestampMilli)
- [TimestampMicro](#TimestampMicro)
- [TimestampNano](#TimestampNano)
<div STYLE="page-break-after: always;"></div>
@@ -65,7 +71,7 @@ import (
## 注:
1. 方法 FormatTimeToStr 和 FormatStrToTime 中的 format 参数值需要传以下类型之一:
1. 函数中`format`参数值需要传以下值之一 (忽略大小写):
- yyyy-mm-dd hh:mm:ss
- yyyy-mm-dd hh:mm
@@ -76,14 +82,18 @@ import (
- dd-mm-yy hh:mm:ss
- yyyy/mm/dd hh:mm:ss
- yyyy/mm/dd hh:mm
- yyyy-mm-dd hh
- yyyy/mm/dd hh
- yyyy/mm/dd
- yyyy/mm
- mm/dd
- dd/mm/yy hh:mm:ss
- yyyymmdd
- mmddyy
- yyyy
- yy
- mm
- hh:mm:ss
- hh:mm
- mm:ss
### <span id="AddDay">AddDay</span>
@@ -643,14 +653,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentDate := datetime.GetNowDate()
fmt.Println(currentDate)
// Output:
@@ -675,15 +682,12 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
currentTime := datetime.GetNowTime()
fmt.Println(currentTime) // 15:57:33
fmt.Println(currentTime)
// Output:
// 15:57:33
@@ -707,14 +711,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
current := datetime.GetNowDateTime()
fmt.Println(current)
// Output:
@@ -722,6 +723,64 @@ func main() {
}
```
### <span id="GetTodayStartTime">GetTodayStartTime</span>
<p>返回当天开始时间, 格式: yyyy-mm-dd 00:00:00。</p>
<b>函数签名:</b>
```go
func GetTodayStartTime() string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
startTime := datetime.GetTodayStartTime()
fmt.Println(startTime)
// Output:
// 2023-06-29 00:00:00
}
```
### <span id="GetTodayEndTime">GetTodayEndTime</span>
<p>返回当天结束时间,格式: yyyy-mm-dd 23:59:59。</p>
<b>函数签名:</b>
```go
func GetTodayEndTime() string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
endTime := datetime.GetTodayEndTime()
fmt.Println(endTime)
// Output:
// 2023-06-29 23:59:59
}
```
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
<p>获取零点时间戳(timestamp of 00:00)</p>
@@ -739,14 +798,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
zeroTime := datetime.GetZeroHourTimestamp()
fmt.Println(zeroTime)
// Output:
@@ -771,14 +827,11 @@ package main
import (
"fmt"
"time"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
now := time.Now()
nightTime := datetime.GetNightTimestamp()
fmt.Println(nightTime)
// Output:
@@ -793,7 +846,7 @@ func main() {
<b>函数签名:</b>
```go
func FormatTimeToStr(t time.Time, format string) string
func FormatTimeToStr(t time.Time, format string, timezone ...string) string
```
<b>示例:</b>
@@ -832,7 +885,7 @@ func main() {
<b>函数签名:</b>
```go
func FormatStrToTime(str, format string) (time.Time, error)
func FormatStrToTime(str, format string, timezone ...string) (time.Time, error)
```
<b>示例:</b>
@@ -1218,7 +1271,7 @@ func main() {
}
```
### <span id="IsWeekend">IsWeekend</span>
### <span id="IsWeekend">IsWeekend(已废弃, 使用 '== Weekday'</span>
<p>判断日期是否是周末。</p>
@@ -1257,3 +1310,158 @@ func main() {
// false
}
```
### <span id="NowDateOrTime">NowDateOrTime</span>
<p>根据指定的格式和时区返回当前时间字符串。</p>
<b>函数签名:</b>
```go
func NowDateOrTime(format string, timezone ...string) string
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
result1 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss")
result2 := datetime.NowDateOrTime("yyyy-mm-dd hh:mm:ss", "EST")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 2023-07-26 15:01:30
// 2023-07-26 02:01:30
}
```
### <span id="Timestamp">Timestamp</span>
<p>返回当前秒级时间戳。</p>
<b>函数签名:</b>
```go
func Timestamp(timezone ...string) int64
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.Timestamp()
fmt.Println(ts)
// Output:
// 1690363051
}
```
### <span id="TimestampMilli">TimestampMilli</span>
<p>返回当前毫秒级时间戳。</p>
<b>函数签名:</b>
```go
func TimestampMilli(timezone ...string) int64
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampMilli()
fmt.Println(ts)
// Output:
// 1690363051331
}
```
### <span id="TimestampMicro">TimestampMicro</span>
<p>返回当前微秒级时间戳。</p>
<b>函数签名:</b>
```go
func TimestampMicro(timezone ...string) int64
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampMicro()
fmt.Println(ts)
// Output:
// 1690363051331784
}
```
### <span id="TimestampNano">TimestampNano</span>
<p>返回当前纳秒级时间戳。</p>
<b>函数签名:</b>
```go
func TimestampNano(timezone ...string) int64
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/datetime"
)
func main() {
ts := datetime.TimestampNano()
fmt.Println(ts)
// Output:
// 1690363051331788000
}
```

View File

@@ -108,7 +108,7 @@ func main() {
### <span id="CreateDir">CreateDir</span>
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
<p>Create directory in absolute path. param `absPath` like /a, /a/b.</p>
<b>Signature:</b>
@@ -127,7 +127,7 @@ import (
)
func main() {
err := fileutil.CreateDir("/a/")
err := fileutil.CreateDir("/a/b") // will create folder /a/b
fmt.Println(err)
}
```
@@ -484,7 +484,7 @@ func main() {
<b>Signature:</b>
```go
func ZipAppendEntry(fpath string, destPath string) error
func ZipAppendEntry(fpath string, destPath string) error
```
<b>Example:</b>
@@ -714,18 +714,30 @@ import (
)
func main() {
fpath := "./test.csv"
fileutil.CreateFile(fpath)
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
data := [][]string{
{"Lili", "22", "female"},
{"Jim", "21", "male"},
}
err := WriteCsvFile("./testdata/test2.csv", data, false)
fmt.Println(err)
err := fileutil.WriteCsvFile(fpath, data, false)
content, _ := ReadCsvFile("./testdata/test2.csv")
if err != nil {
return
}
content, err := fileutil.ReadCsvFile(fpath)
if err != nil {
return
}
fmt.Println(content)
// Output:
// <nil>
// [[Lili 22 female] [Jim 21 male]]
}
```

View File

@@ -108,7 +108,7 @@ func main() {
### <span id="CreateDir">CreateDir</span>
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b</p>
<b>函数签名:</b>
@@ -127,7 +127,7 @@ import (
)
func main() {
err := fileutil.CreateDir("/a/")
err := fileutil.CreateDir("/a/b") // will create folder /a/b
fmt.Println(err)
}
```
@@ -714,18 +714,30 @@ import (
)
func main() {
fpath := "./test.csv"
fileutil.CreateFile(fpath)
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
data := [][]string{
{"Lili", "22", "female"},
{"Jim", "21", "male"},
}
err := WriteCsvFile("./testdata/test2.csv", data, false)
fmt.Println(err)
err := fileutil.WriteCsvFile(fpath, data, false)
content, _ := ReadCsvFile("./testdata/test2.csv")
if err != nil {
return
}
content, err := fileutil.ReadCsvFile(fpath)
if err != nil {
return
}
fmt.Println(content)
// Output:
// <nil>
// [[Lili 22 female] [Jim 21 male]]
}
```

View File

@@ -43,12 +43,20 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [IsDisjoint](#IsDisjoint)
- [HasKey](#HasKey)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
- [ConcurrentMap_GetOrSet](#ConcurrentMap_GetOrSet)
- [ConcurrentMap_Delete](#ConcurrentMap_Delete)
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
- [ConcurrentMap_Has](#ConcurrentMap_Has)
- [ConcurrentMap_Range](#ConcurrentMap_Range)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="MapTo">MapTo</span>
<p>Rry to map any interface to struct or base type.</p>
@@ -893,7 +901,7 @@ func main() {
### <span id="IsDisjoint">IsDisjoint</span>
<p>Checks two maps are disjoint if they have no keys in common</p>
<p>Checks two maps are disjoint if they have no keys in common.</p>
<b>Signature:</b>
@@ -937,3 +945,421 @@ func main() {
// false
}
```
### <span id="HasKey">HasKey</span>
<p>Checks if map has key or not. This function is used to replace the following boilerplate code:</p>
```go
_, haskey := amap["baz"];
if haskey {
fmt.Println("map has key baz")
}
```
<b>Signature:</b>
```go
func HasKey[K comparable, V any](m map[K]V, key K) bool
```
<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,
}
result1 := maputil.HasKey(m, "a")
result2 := maputil.HasKey(m, "c")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="NewConcurrentMap">NewConcurrentMap</span>
<p>ConcurrentMap is like map, but is safe for concurrent use by multiple goroutines.</p>
<b>Signature:</b>
```go
// NewConcurrentMap create a ConcurrentMap with specific shard count.
func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V]
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
// create a ConcurrentMap whose key type is string, value type is int
cm := maputil.NewConcurrentMap[string, int](100)
}
```
### <span id="ConcurrentMap_Set">ConcurrentMap_Set</span>
<p>Set the value for a key.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) Set(key K, value V)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok)
wg2.Done()
}(j)
}
wg2.Wait()
// output: (order may change)
// 1 true
// 3 true
// 2 true
// 0 true
// 4 true
}
```
### <span id="ConcurrentMap_Get">ConcurrentMap_Get</span>
<p>Get the value stored in the map for a key, or nil if no.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok)
wg2.Done()
}(j)
}
wg2.Wait()
// output: (order may change)
// 1 true
// 3 true
// 2 true
// 0 true
// 4 true
}
```
### <span id="ConcurrentMap_GetOrSet">ConcurrentMap_GetOrSet</span>
<p>Returns the existing value for the key if present. Otherwise, it sets and returns the given value.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
val, ok := cm.GetOrSet(fmt.Sprintf("%d", n), n)
fmt.Println(val, ok)
wg.Done()
}(i)
}
wg.Wait()
// output: (order may change)
// 1 false
// 3 false
// 2 false
// 0 false
// 4 false
}
```
### <span id="ConcurrentMap_Delete">ConcurrentMap_Delete</span>
<p>Delete the value for a key.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) Delete(key K)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
cm.Delete(fmt.Sprintf("%d", n))
wg2.Done()
}(j)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_GetAndDelete">ConcurrentMap_GetAndDelete</span>
<p>Returns the existing value for the key if present and then delete the value for the key. Otherwise, do nothing, just return false.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
fmt.Println(val, ok) //n, true
_, ok = cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok) //false
wg2.Done()
}(j)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_Has">ConcurrentMap_Has</span>
<p>Checks if map has the value for a key.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) Has(key K) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
ok := cm.Has(fmt.Sprintf("%d", n))
fmt.Println(ok) // true
wg2.Done()
}(j)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_Range">ConcurrentMap_Range</span>
<p>Calls iterator sequentially for each key and value present in each of the shards in the map. If iterator returns false, range stops the iteration.</p>
<b>Signature:</b>
```go
func (cm *ConcurrentMap[K, V]) Range(iterator func(key K, value V) bool)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
cm.Range(func(key string, value int) bool {
fmt.Println(value)
return true
})
}
```

View File

@@ -43,6 +43,16 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [IsDisjoint](#IsDisjoint)
- [HasKey](#HasKey)
- [NewConcurrentMap](#NewConcurrentMap)
- [ConcurrentMap_Get](#ConcurrentMap_Get)
- [ConcurrentMap_Set](#ConcurrentMap_Set)
- [ConcurrentMap_GetOrSet](#ConcurrentMap_GetOrSet)
- [ConcurrentMap_Delete](#ConcurrentMap_Delete)
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
- [ConcurrentMap_Has](#ConcurrentMap_Has)
- [ConcurrentMap_Range](#ConcurrentMap_Range)
<div STYLE="page-break-after: always;"></div>
@@ -932,3 +942,419 @@ func main() {
// false
}
```
### <span id="HasKey">HasKey</span>
<p>检查map是否包含某个key。用于代替以下样板代码:</p>
```go
_, haskey := amap["baz"];
if haskey {
fmt.Println("map has key baz")
}
```
<b>函数签名:</b>
```go
func HasKey[K comparable, V any](m map[K]V, key K) bool
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
}
result1 := maputil.HasKey(m, "a")
result2 := maputil.HasKey(m, "c")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="NewConcurrentMap">NewConcurrentMap</span>
<p>ConcurrentMap协程安全的map结构。</p>
<b>函数签名:</b>
```go
// NewConcurrentMap create a ConcurrentMap with specific shard count.
func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V]
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
// create a ConcurrentMap whose key type is string, value type is int
cm := maputil.NewConcurrentMap[string, int](100)
}
```
### <span id="ConcurrentMap_Set">ConcurrentMap_Set</span>
<p>在map中设置key和value。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) Set(key K, value V)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok)
wg2.Done()
}(j)
}
wg2.Wait()
// output: (order may change)
// 1 true
// 3 true
// 2 true
// 0 true
// 4 true
}
```
### <span id="ConcurrentMap_Get">ConcurrentMap_Get</span>
<p>根据key获取value, 如果不存在key,返回零值。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok)
wg2.Done()
}(j)
}
wg2.Wait()
// output: (order may change)
// 1 true
// 3 true
// 2 true
// 0 true
// 4 true
}
```
### <span id="ConcurrentMap_GetOrSet">ConcurrentMap_GetOrSet</span>
<p>返回键的现有值如果存在否则设置key并返回给定值。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
val, ok := cm.GetOrSet(fmt.Sprintf("%d", n), n)
fmt.Println(val, ok)
wg.Done()
}(i)
}
wg.Wait()
// output: (order may change)
// 1 false
// 3 false
// 2 false
// 0 false
// 4 false
}
```
### <span id="ConcurrentMap_Delete">ConcurrentMap_Delete</span>
<p>删除key。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) Delete(key K)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
cm.Delete(fmt.Sprintf("%d", n))
wg2.Done()
}(i)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_GetAndDelete">ConcurrentMap_GetAndDelete</span>
<p>获取key然后删除。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
fmt.Println(val, ok) //n, true
_, ok = cm.Get(fmt.Sprintf("%d", n))
fmt.Println(val, ok) //false
wg2.Done()
}(j)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_Has">ConcurrentMap_Has</span>
<p>验证是否包含key。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) Has(key K) bool
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(5)
for j := 0; j < 5; j++ {
go func(n int) {
ok := cm.Has(fmt.Sprintf("%d", n))
fmt.Println(ok) // true
wg2.Done()
}(j)
}
wg2.Wait()
}
```
### <span id="ConcurrentMap_Range">ConcurrentMap_Range</span>
<p>为map中每个键和值顺序调用迭代器。 如果iterator返回false则停止迭代。</p>
<b>函数签名:</b>
```go
func (cm *ConcurrentMap[K, V]) Range(iterator func(key K, value V) bool)
```
<b>实例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
)
func main() {
cm := maputil.NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
cm.Range(func(key string, value int) bool {
fmt.Println(value)
return true
})
}
```

View File

@@ -46,6 +46,8 @@ import (
- [Sin](#Sin)
- [Log](#Log)
- [Sum](#Sum)
- [Abs](#Abs)
<div STYLE="page-break-after: always;"></div>
@@ -942,4 +944,40 @@ func main() {
// 3
// 1.1
}
```
### <span id="Abs">Abs</span>
<p>Returns the absolute value of x.</p>
<b>Signature:</b>
```go
func Abs[T constraints.Integer | constraints.Float](x T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := Abs(-1)
result2 := Abs(-0.1)
result3 := Abs(float32(0.2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 0.1
// 0.2
}
```

View File

@@ -46,6 +46,7 @@ import (
- [Sin](#Sin)
- [Log](#Log)
- [Sum](#Sum)
- [Abs](#Abs)
<div STYLE="page-break-after: always;"></div>
@@ -941,3 +942,39 @@ func main() {
// 1.1
}
```
### <span id="Abs">Abs</span>
<p>求绝对值。</p>
<b>函数签名:</b>
```go
func Abs[T constraints.Integer | constraints.Float](x T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/mathutil"
)
func main() {
result1 := Abs(-1)
result2 := Abs(-0.1)
result3 := Abs(float32(0.2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 0.1
// 0.2
}
```

229
docs/pointer.md Normal file
View File

@@ -0,0 +1,229 @@
# Pointer
pointer contains some util functions to operate go pointer.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/pointer/pointer.go](https://github.com/duke-git/lancet/blob/main/pointer/pointer.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/pointer"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Of](#Of)
- [Unwrap](#Unwrap)
- [UnwarpOr](#UnwarpOr)
- [UnwarpOrDefault](#UnwarpOrDefault)
- [ExtractPointer](#ExtractPointer)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Of">Of</span>
<p>Returns a pointer to the pass value `v`.</p>
<b>Signature:</b>
```go
func Of[T any](v T) *T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
result1 := pointer.Of(123)
result2 := pointer.Of("abc")
fmt.Println(*result1)
fmt.Println(*result2)
// Output:
// 123
// abc
}
```
### <span id="Unwrap">Unwrap</span>
<p>Returns the value from the pointer.</p>
<b>Signature:</b>
```go
func Unwrap[T any](p *T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
result1 := pointer.Unwrap(&a)
result2 := pointer.Unwrap(&b)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 123
// abc
}
```
### <span id="UnwarpOr">UnwarpOr</span>
<p>Returns the value from the pointer or fallback if the pointer is nil.</p>
<b>Signature:</b>
```go
UnwarpOr[T any](p *T, fallback T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOr(&a, 456)
result2 := pointer.UnwarpOr(&b, "abc")
result3 := pointer.UnwarpOr(c, 456)
result4 := pointer.UnwarpOr(d, "def")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 456
// def
}
```
### <span id="UnwarpOrDefault">UnwarpOrDefault</span>
<p>Returns the value from the pointer or the default value if the pointer is nil.</p>
<b>Signature:</b>
```go
UnwarpOrDefault[T any](p *T) T
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOrDefault(&a)
result2 := pointer.UnwarpOrDefault(&b)
result3 := pointer.UnwarpOrDefault(c)
result4 := pointer.UnwarpOrDefault(d)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 0
//
}
```
### <span id="ExtractPointer">ExtractPointer</span>
<p>Returns the underlying value by the given interface type</p>
<b>Signature:</b>
```go
func ExtractPointer(value any) any
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 1
b := &a
c := &b
d := &c
result := pointer.ExtractPointer(d)
fmt.Println(result)
// Output:
// 1
}
```

227
docs/pointer_zh-CN.md Normal file
View File

@@ -0,0 +1,227 @@
# Pointer
pointer 包支持一些指针类型的操作。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/pointer/pointer.go](https://github.com/duke-git/lancet/blob/main/pointer/pointer.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/pointer"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Of](#Of)
- [Unwrap](#Unwrap)
- [ExtractPointer](#ExtractPointer)
- [UnwarpOr](#UnwarpOr)
- [UnwarpOrDefault](#UnwarpOrDefault)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Of">Of</span>
<p>返回传入参数的指针值。</p>
<b>函数签名:</b>
```go
func Of[T any](v T) *T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
result1 := pointer.Of(123)
result2 := pointer.Of("abc")
fmt.Println(*result1)
fmt.Println(*result2)
// Output:
// 123
// abc
}
```
### <span id="Unwrap">Unwrap</span>
<p>返回传入指针指向的值。</p>
<b>函数签名:</b>
```go
func Unwrap[T any](p *T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
result1 := pointer.Unwrap(&a)
result2 := pointer.Unwrap(&b)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 123
// abc
}
```
### <span id="ExtractPointer">ExtractPointer</span>
<p>返回传入interface的底层值。</p>
<b>函数签名:</b>
```go
func ExtractPointer(value any) any
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 1
b := &a
c := &b
d := &c
result := pointer.ExtractPointer(d)
fmt.Println(result)
// Output:
// 1
}
```
### <span id="UnwarpOr">UnwarpOr</span>
<p>返回指针的值如果指针为零值则返回fallback。</p>
<b>函数签名:</b>
```go
UnwarpOr[T any](p *T, fallback T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOr(&a, 456)
result2 := pointer.UnwarpOr(&b, "abc")
result3 := pointer.UnwarpOr(c, 456)
result4 := pointer.UnwarpOr(d, "def")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 456
// def
}
```
### <span id="UnwarpOrDefault">UnwarpOrDefault</span>
<p>返回指针的值,如果指针为零值,则返回相应零值。</p>
<b>函数签名:</b>
```go
UnwarpOrDefault[T any](p *T) T
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/pointer"
)
func main() {
a := 123
b := "abc"
var c *int
var d *string
result1 := pointer.UnwarpOrDefault(&a)
result2 := pointer.UnwarpOrDefault(&b)
result3 := pointer.UnwarpOrDefault(c)
result4 := pointer.UnwarpOrDefault(d)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 0
//
}
```

View File

@@ -269,7 +269,7 @@ import (
)
func main() {
result := RandUniqueIntSlice(5, 0, 10)
result := random.RandUniqueIntSlice(5, 0, 10)
fmt.Println(result) //[0 4 7 1 5] (random)
}
```

View File

@@ -268,7 +268,7 @@ import (
)
func main() {
result := RandUniqueIntSlice(5, 0, 10)
result := random.RandUniqueIntSlice(5, 0, 10)
fmt.Println(result) //[0 4 7 1 5] (random)
}
```

View File

@@ -90,6 +90,7 @@ import (
- [UpdateAt](#UpdateAt)
- [Without](#Without)
- [KeyBy](#KeyBy)
- [Join](#Join)
<div STYLE="page-break-after: always;"></div>
@@ -2417,3 +2418,36 @@ func main() {
// map[1:a 2:ab 3:abc]
}
```
### <span id="Join">Join</span>
<p>Join the slice item with specify separator.</p>
<b>Signature:</b>
```go
func Join[T any](s []T, separator string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
result1 := slice.Join(nums, ",")
result2 := slice.Join(nums, "-")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1,2,3,4,5
// 1-2-3-4-5
}
```

View File

@@ -90,6 +90,7 @@ import (
- [UpdateAt](#UpdateAt)
- [Without](#Without)
- [KeyBy](#KeyBy)
- [Join](#Join)
<div STYLE="page-break-after: always;"></div>
@@ -2390,7 +2391,7 @@ func main() {
### <span id="KeyBy">KeyBy</span>
<p>将切片每个元素调用函数后转为map</p>
<p>将切片每个元素调用函数后转为map</p>
<b>函数签名:</b>
@@ -2417,3 +2418,36 @@ func main() {
// map[1:a 2:ab 3:abc]
}
```
### <span id="Join">Join</span>
<p>用指定的分隔符链接切片元素。</p>
<b>函数签名:</b>
```go
func Join[T any](s []T, separator string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
result1 := slice.Join(nums, ",")
result2 := slice.Join(nums, "-")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1,2,3,4,5
// 1-2-3-4-5
}
```

View File

@@ -34,19 +34,19 @@ import (
<div STYLE="page-break-after: always;"></div>
## Documentation 文档
## 文档
### <span id="IsWindows">IsWindows</span>
<p>检查当前操作系统是否是windows</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func IsWindows() bool
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -64,13 +64,13 @@ func main() {
<p>检查当前操作系统是否是linux</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func IsLinux() bool
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -88,13 +88,13 @@ func main() {
<p>检查当前操作系统是否是macos</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func IsMac() bool
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -112,13 +112,13 @@ func main() {
<p>获取key命名的环境变量的值</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func GetOsEnv(key string) string
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -142,13 +142,13 @@ func main() {
<p>设置由key命名的环境变量的值</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func SetOsEnv(key, value string) error
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -172,13 +172,13 @@ func main() {
<p>删除单个环境变量</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func RemoveOsEnv(key string) error
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -210,13 +210,13 @@ func main() {
<p>获取key命名的环境变量值并与compareEnv进行比较</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
func CompareOsEnv(key, comparedEnv string) bool
```
<b>Example:</b>
<b>示例:</b>
```go
import (
@@ -243,7 +243,7 @@ func main() {
<p>执行shell命令返回命令的stdout和stderr字符串如果出现错误则返回错误。参数`command`是一个完整的命令字符串如ls-alinuxdirwindowsping 127.0.0.1。在linux中使用/bin/bash-c执行命令在windows中使用powershell.exe执行命令。</p>
<b>Signature:</b>
<b>函数签名:</b>
```go
type (
@@ -252,7 +252,7 @@ type (
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
```
<b>Example:</b>
<b>示例:</b>
```go
import (

1197
docs/tuple.md Normal file

File diff suppressed because it is too large Load Diff

1197
docs/tuple_zh-CN.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,8 @@ func CreateFile(path string) bool {
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/.
// Play: https://go.dev/play/p/qUuCe1OGQnM
func CreateDir(absPath string) error {
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
// return os.MkdirAll(path.Dir(absPath), os.ModePerm)
return os.MkdirAll(absPath, os.ModePerm)
}
// IsDir checks if the path is directory or not.
@@ -198,7 +199,15 @@ func IsZipFile(filepath string) bool {
// Zip create zip file, fpath could be a single file or a directory.
// Play: https://go.dev/play/p/j-3sWBp8ik_P
func Zip(fpath string, destPath string) error {
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 {
zipFile, err := os.Create(destPath)
if err != nil {
return err
@@ -208,10 +217,32 @@ func Zip(fpath string, destPath string) error {
archive := zip.NewWriter(zipFile)
defer archive.Close()
return addFileToArchive(fpath, archive)
return addFileToArchive1(filePath, archive)
}
func addFileToArchive(fpath string, archive *zip.Writer) error {
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 {
if err != nil {
return err
@@ -246,10 +277,42 @@ func addFileToArchive(fpath string, archive *zip.Writer) error {
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
}
// UnZip unzip the file and save it to destPath.
// Play: https://go.dev/play/p/g0w34kS7B8m
func UnZip(zipFile string, destPath string) error {
zipReader, err := zip.OpenReader(zipFile)
if err != nil {
return err
@@ -332,7 +395,7 @@ func ZipAppendEntry(fpath string, destPath string) error {
}
}
err = addFileToArchive(fpath, archive)
err = addFileToArchive1(fpath, archive)
if err != nil {
return err
@@ -507,7 +570,7 @@ func ReadCsvFile(filepath string) ([][]string, error) {
}
// WriteCsvFile write content to target csv file.
// Play: todo
// Play: https://go.dev/play/p/dAXm58Q5U1o
func WriteCsvFile(filepath string, records [][]string, append bool) error {
flag := os.O_RDWR | os.O_CREATE

View File

@@ -39,7 +39,7 @@ func ExampleCreateFile() {
func ExampleCreateDir() {
pwd, _ := os.Getwd()
dirPath := pwd + "/test_xxx/"
dirPath := pwd + "/createdir/a/b"
result1 := IsExist(dirPath)
@@ -48,16 +48,22 @@ func ExampleCreateDir() {
return
}
result2 := IsExist(dirPath)
os.Remove(dirPath)
result2 := IsExist(pwd + "/createdir/")
result3 := IsExist(pwd + "/createdir/a")
result4 := IsExist(pwd + "/createdir/a/b")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
os.RemoveAll(pwd + "/createdir/")
// Output:
// false
// true
// true
// true
}
func ExampleIsDir() {

View File

@@ -8,6 +8,8 @@ import (
)
func TestIsExist(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsExist")
cases := []string{"./", "./file.go", "./a.txt"}
@@ -20,6 +22,8 @@ func TestIsExist(t *testing.T) {
}
func TestCreateFile(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCreateFile")
f := "./text.txt"
@@ -36,6 +40,8 @@ func TestCreateFile(t *testing.T) {
}
func TestCreateDir(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCreateDir")
pwd, err := os.Getwd()
@@ -44,7 +50,7 @@ func TestCreateDir(t *testing.T) {
t.FailNow()
}
dirPath := pwd + "/a/"
dirPath := pwd + "/a/b"
err = CreateDir(dirPath)
if err != nil {
t.Error(err)
@@ -52,11 +58,15 @@ func TestCreateDir(t *testing.T) {
}
assert.Equal(true, IsExist(dirPath))
os.Remove(dirPath)
os.RemoveAll(pwd + "/a")
assert.Equal(false, IsExist(dirPath))
}
func TestIsDir(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsDir")
cases := []string{"./", "./a.txt"}
@@ -69,6 +79,8 @@ func TestIsDir(t *testing.T) {
}
func TestRemoveFile(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRemoveFile")
f := "./text.txt"
if !IsExist(f) {
@@ -229,6 +241,19 @@ func TestZipAppendEntry(t *testing.T) {
os.RemoveAll(unZipPath)
}
func TestZipFolder(t *testing.T) {
// assert := internal.NewAssert(t, "TestZipFolder")
// toZipFolder := "./tempdir/a/b"
// zipFolder := "./tempdir/a/b.zip"
// err := Zip(toZipFolder, zipFolder)
// assert.IsNil(err)
// assert.Equal(true, IsExist(zipFolder))
// os.Remove(zipFolder)
}
func TestFileMode(t *testing.T) {
assert := internal.NewAssert(t, "TestFileMode")

View File

@@ -7,6 +7,8 @@ import (
)
func TestDecimalBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDecimalBytes")
assert.Equal("1KB", DecimalBytes(1000))
@@ -21,6 +23,8 @@ func TestDecimalBytes(t *testing.T) {
}
func TestBinaryBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBinaryBytes")
assert.Equal("1KiB", BinaryBytes(1024))
@@ -30,6 +34,8 @@ func TestBinaryBytes(t *testing.T) {
}
func TestParseDecimalBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestParseDecimalBytes")
cases := map[string]uint64{
@@ -58,6 +64,8 @@ func TestParseDecimalBytes(t *testing.T) {
}
func TestParseBinaryBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestParseBinaryBytes")
cases := map[string]uint64{

View File

@@ -8,6 +8,8 @@ import (
)
func TestComma(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestComma")
assert.Equal("", Comma("", ""))
@@ -29,6 +31,8 @@ func TestComma(t *testing.T) {
}
func TestPretty(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPretty")
cases := []any{
@@ -60,6 +64,8 @@ func TestPretty(t *testing.T) {
}
func TestPrettyToWriter(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPrettyToWriter")
type User struct {

View File

@@ -11,6 +11,8 @@ import (
)
func TestAfter(t *testing.T) {
t.Parallel()
arr := []string{"a", "b"}
f := After(len(arr), func(i int) int {
fmt.Println("print done")
@@ -34,6 +36,8 @@ func TestAfter(t *testing.T) {
}
func TestBefore(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBefore")
arr := []string{"a", "b", "c", "d", "e"}
@@ -57,6 +61,8 @@ func TestBefore(t *testing.T) {
}
func TestCurry(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCurry")
add := func(a, b int) int {
@@ -71,6 +77,8 @@ func TestCurry(t *testing.T) {
}
func TestCompose(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCompose")
toUpper := func(strs ...string) string {

View File

@@ -7,6 +7,8 @@ import (
)
func TestWatcher(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestWatcher")
w := NewWatcher()

View File

@@ -12,6 +12,8 @@ import (
)
func TestSliceIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSliceIterator")
// HashNext
@@ -60,6 +62,8 @@ func TestSliceIterator(t *testing.T) {
}
func TestRangeIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRangeIterator")
t.Run("range iterator: ", func(t *testing.T) {
@@ -85,6 +89,8 @@ func TestRangeIterator(t *testing.T) {
}
func TestChannelIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRangeIterator")
iter := FromSlice([]int{1, 2, 3, 4})

View File

@@ -17,6 +17,8 @@ import (
)
func TestMapIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapIterator")
iter := FromSlice([]int{1, 2, 3, 4})
@@ -28,6 +30,8 @@ func TestMapIterator(t *testing.T) {
}
func TestFilterIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilterIterator")
iter := FromSlice([]int{1, 2, 3, 4})
@@ -39,6 +43,8 @@ func TestFilterIterator(t *testing.T) {
}
func TestJoinIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestJoinIterator")
iter1 := FromSlice([]int{1, 2})
@@ -54,6 +60,8 @@ func TestJoinIterator(t *testing.T) {
}
func TestReduce(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReduce")
iter := FromSlice([]int{1, 2, 3, 4})
@@ -62,6 +70,8 @@ func TestReduce(t *testing.T) {
}
func TestTakeIterator(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTakeIterator")
iter := FromSlice([]int{1, 2, 3, 4, 5})

156
maputil/concurrentmap.go Normal file
View File

@@ -0,0 +1,156 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package maputil includes some functions to manipulate map.
package maputil
import (
"fmt"
"sync"
)
const defaultShardCount = 32
// ConcurrentMap is like map, but is safe for concurrent use by multiple goroutines.
type ConcurrentMap[K comparable, V any] struct {
shardCount uint64
locks []sync.RWMutex
maps []map[K]V
}
// NewConcurrentMap create a ConcurrentMap with specific shard count.
// Play: https://go.dev/play/p/3PenTPETJT0
func NewConcurrentMap[K comparable, V any](shardCount int) *ConcurrentMap[K, V] {
if shardCount <= 0 {
shardCount = defaultShardCount
}
cm := &ConcurrentMap[K, V]{
shardCount: uint64(shardCount),
locks: make([]sync.RWMutex, shardCount),
maps: make([]map[K]V, shardCount),
}
for i := range cm.maps {
cm.maps[i] = make(map[K]V)
}
return cm
}
// Set the value for a key.
// Play: https://go.dev/play/p/3PenTPETJT0
func (cm *ConcurrentMap[K, V]) Set(key K, value V) {
shard := cm.getShard(key)
cm.locks[shard].Lock()
cm.maps[shard][key] = value
cm.locks[shard].Unlock()
}
// Get the value stored in the map for a key, or nil if no.
// Play: https://go.dev/play/p/3PenTPETJT0
func (cm *ConcurrentMap[K, V]) Get(key K) (V, bool) {
shard := cm.getShard(key)
cm.locks[shard].RLock()
value, ok := cm.maps[shard][key]
cm.locks[shard].RUnlock()
return value, ok
}
// GetOrSet returns the existing value for the key if present.
// Otherwise, it sets and returns the given value.
// Play: https://go.dev/play/p/aDcDApOK01a
func (cm *ConcurrentMap[K, V]) GetOrSet(key K, value V) (actual V, ok bool) {
shard := cm.getShard(key)
cm.locks[shard].RLock()
if actual, ok := cm.maps[shard][key]; ok {
cm.locks[shard].RUnlock()
return actual, ok
}
cm.locks[shard].RUnlock()
// lock again
cm.locks[shard].Lock()
if actual, ok = cm.maps[shard][key]; ok {
cm.locks[shard].Unlock()
return
}
cm.maps[shard][key] = value
cm.locks[shard].Unlock()
return value, ok
}
// Delete the value for a key.
// Play: https://go.dev/play/p/uTIJZYhpVMS
func (cm *ConcurrentMap[K, V]) Delete(key K) {
shard := cm.getShard(key)
cm.locks[shard].Lock()
delete(cm.maps[shard], key)
cm.locks[shard].Unlock()
}
// GetAndDelete returns the existing value for the key if present and then delete the value for the key.
// Otherwise, do nothing, just return false
// Play: https://go.dev/play/p/ZyxeIXSZUiM
func (cm *ConcurrentMap[K, V]) GetAndDelete(key K) (actual V, ok bool) {
shard := cm.getShard(key)
cm.locks[shard].RLock()
if actual, ok = cm.maps[shard][key]; ok {
cm.locks[shard].RUnlock()
cm.Delete(key)
return
}
cm.locks[shard].RUnlock()
return actual, false
}
// Has checks if map has the value for a key.
// Play: https://go.dev/play/p/C8L4ul9TVwf
func (cm *ConcurrentMap[K, V]) Has(key K) bool {
_, ok := cm.Get(key)
return ok
}
// Range calls iterator sequentially for each key and value present in each of the shards in the map.
// If iterator returns false, range stops the iteration.
// Play: https://go.dev/play/p/iqcy7P8P0Pr
func (cm *ConcurrentMap[K, V]) Range(iterator func(key K, value V) bool) {
for shard := range cm.locks {
cm.locks[shard].RLock()
for k, v := range cm.maps[shard] {
if !iterator(k, v) {
cm.locks[shard].RUnlock()
return
}
}
cm.locks[shard].RUnlock()
}
}
// getShard get shard by a key.
func (cm *ConcurrentMap[K, V]) getShard(key K) uint64 {
hash := fnv32(fmt.Sprintf("%v", key))
return uint64(hash) % cm.shardCount
}
func fnv32(key string) uint32 {
hash := uint32(2166136261)
const prime32 = uint32(16777619)
keyLength := len(key)
for i := 0; i < keyLength; i++ {
hash *= prime32
hash ^= uint32(key[i])
}
return hash
}

View File

@@ -0,0 +1,174 @@
package maputil
import (
"fmt"
"sync"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestConcurrentMap_Set_Get(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_Set_Get")
cm := NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
for j := 0; j < 10; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
assert.Equal(n, val)
assert.Equal(true, ok)
}(j)
}
}
func TestConcurrentMap_GetOrSet(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_GetOrSet")
cm := NewConcurrentMap[string, int](100)
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(n int) {
val, ok := cm.GetOrSet(fmt.Sprintf("%d", n), n)
assert.Equal(n, val)
assert.Equal(false, ok)
wg.Done()
}(i)
}
wg.Wait()
for j := 0; j < 5; j++ {
go func(n int) {
val, ok := cm.Get(fmt.Sprintf("%d", n))
assert.Equal(n, val)
assert.Equal(true, ok)
}(j)
}
}
func TestConcurrentMap_Delete(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_Delete")
cm := NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Delete(fmt.Sprintf("%d", n))
wg2.Done()
}(i)
}
wg2.Wait()
for j := 0; j < 10; j++ {
go func(n int) {
_, ok := cm.Get(fmt.Sprintf("%d", n))
assert.Equal(false, ok)
}(j)
}
}
func TestConcurrentMap_GetAndDelete(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_GetAndDelete")
cm := NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
var wg2 sync.WaitGroup
wg2.Add(10)
for j := 0; j < 10; j++ {
go func(n int) {
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
assert.Equal(n, val)
assert.Equal(true, ok)
_, ok = cm.Get(fmt.Sprintf("%d", n))
assert.Equal(false, ok)
wg2.Done()
}(j)
}
wg2.Wait()
}
func TestConcurrentMap_Has(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_Has")
cm := NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
for j := 0; j < 10; j++ {
go func(n int) {
ok := cm.Has(fmt.Sprintf("%d", n))
assert.Equal(true, ok)
}(j)
}
}
func TestConcurrentMap_Range(t *testing.T) {
assert := internal.NewAssert(t, "TestConcurrentMap_Range")
cm := NewConcurrentMap[string, int](100)
var wg1 sync.WaitGroup
wg1.Add(10)
for i := 0; i < 10; i++ {
go func(n int) {
cm.Set(fmt.Sprintf("%d", n), n)
wg1.Done()
}(i)
}
wg1.Wait()
cm.Range(func(key string, value int) bool {
assert.Equal(key, fmt.Sprintf("%d", value))
return true
})
}

View File

@@ -289,3 +289,17 @@ func MapValues[K comparable, V any, T any](m map[K]V, iteratee func(key K, value
return result
}
// HasKey checks if map has key or not.
// This function is used to replace the following boilerplate code:
// _, haskey := amap["baz"];
//
// if haskey {
// fmt.Println("map has key baz")
// }
//
// Play: https://go.dev/play/p/isZZHOsDhFc
func HasKey[K comparable, V any](m map[K]V, key K) bool {
_, haskey := m[key]
return haskey
}

View File

@@ -433,3 +433,20 @@ func ExampleMapTo() {
// <nil>
// {Nothin 28 123456789 {test 1}}
}
func ExampleHasKey() {
m := map[string]int{
"a": 1,
"b": 2,
}
result1 := HasKey(m, "a")
result2 := HasKey(m, "c")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}

View File

@@ -9,6 +9,8 @@ import (
)
func TestKeys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestKeys")
m := map[int]string{
@@ -26,6 +28,8 @@ func TestKeys(t *testing.T) {
}
func TestValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestValues")
m := map[int]string{
@@ -43,6 +47,8 @@ func TestValues(t *testing.T) {
}
func TestKeysBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestKeysBy")
m := map[int]string{
@@ -61,6 +67,8 @@ func TestKeysBy(t *testing.T) {
}
func TestValuesBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestValuesBy")
m := map[int]string{
@@ -88,6 +96,8 @@ func TestValuesBy(t *testing.T) {
}
func TestMerge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMerge")
m1 := map[int]string{
@@ -110,6 +120,8 @@ func TestMerge(t *testing.T) {
}
func TestForEach(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
m := map[string]int{
@@ -129,6 +141,8 @@ func TestForEach(t *testing.T) {
}
func TestFilter(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilter")
m := map[string]int{
@@ -151,6 +165,8 @@ func TestFilter(t *testing.T) {
}
func TestFilterByKeys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilterByKeys")
m := map[string]int{
@@ -170,6 +186,8 @@ func TestFilterByKeys(t *testing.T) {
}
func TestFilterByValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilterByValues")
m := map[string]int{
@@ -189,6 +207,8 @@ func TestFilterByValues(t *testing.T) {
}
func TestOmitBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOmitBy")
m := map[string]int{
@@ -212,6 +232,8 @@ func TestOmitBy(t *testing.T) {
}
func TestOmitByKeys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOmitByKeys")
m := map[string]int{
@@ -232,6 +254,8 @@ func TestOmitByKeys(t *testing.T) {
}
func TestOmitByValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOmitByValues")
m := map[string]int{
@@ -252,6 +276,8 @@ func TestOmitByValues(t *testing.T) {
}
func TestIntersect(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntersect")
m1 := map[string]int{
@@ -279,6 +305,8 @@ func TestIntersect(t *testing.T) {
}
func TestMinus(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMinus")
m1 := map[string]int{
@@ -297,6 +325,8 @@ func TestMinus(t *testing.T) {
}
func TestIsDisjoint(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMinus")
m1 := map[string]int{
@@ -319,6 +349,8 @@ func TestIsDisjoint(t *testing.T) {
}
func TestEntries(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEntries")
m := map[string]int{
@@ -339,6 +371,8 @@ func TestEntries(t *testing.T) {
}
func TestFromEntries(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromEntries")
result := FromEntries([]Entry[string, int]{
@@ -354,6 +388,8 @@ func TestFromEntries(t *testing.T) {
}
func TestTransform(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTransform")
m := map[string]int{
@@ -376,6 +412,8 @@ func TestTransform(t *testing.T) {
}
func TestMapKeys(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapKeys")
m := map[int]string{
@@ -398,6 +436,8 @@ func TestMapKeys(t *testing.T) {
}
func TestMapValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapKeys")
m := map[int]string{
@@ -418,3 +458,17 @@ func TestMapValues(t *testing.T) {
assert.Equal(expected, result)
}
func TestHasKey(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHasKey")
m := map[string]int{
"a": 1,
"b": 2,
}
assert.Equal(true, HasKey(m, "a"))
assert.Equal(false, HasKey(m, "c"))
}

View File

@@ -21,6 +21,8 @@ type (
)
func TestStructType(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStructType")
src := map[string]interface{}{
@@ -44,6 +46,8 @@ func TestStructType(t *testing.T) {
}
func TestBaseType(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBaseType")
tc := map[string]interface{}{
@@ -90,22 +94,31 @@ func TestBaseType(t *testing.T) {
MapTo(tc["i"], &number)
assert.EqualValues(-1, number)
MapTo(tc["i8"], &number)
assert.EqualValues(-8, number)
MapTo(tc["i16"], &number)
assert.EqualValues(-16, number)
MapTo(tc["i32"], &number)
assert.EqualValues(-32, number)
MapTo(tc["i64"], &number)
assert.EqualValues(-64, number)
MapTo(tc["u"], &number)
assert.EqualValues(1, number)
MapTo(tc["u8"], &number)
assert.EqualValues(8, number)
MapTo(tc["u16"], &number)
assert.EqualValues(16, number)
MapTo(tc["u32"], &number)
assert.EqualValues(32, number)
MapTo(tc["u64"], &number)
assert.EqualValues(64, number)
}

View File

@@ -173,7 +173,7 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
}
// Sum return sum of passed numbers.
// Play: todo
// Play: https://go.dev/play/p/1To2ImAMJA7
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T {
var sum T
@@ -337,7 +337,17 @@ func Sin(radian float64, precision ...int) float64 {
}
// Log returns the logarithm of base n.
// Play: todo
// Play: https://go.dev/play/p/_d4bi8oyhat
func Log(n, base float64) float64 {
return math.Log(n) / math.Log(base)
}
// Abs returns the absolute value of x.
// Play: todo
func Abs[T constraints.Integer | constraints.Float](x T) T {
if x < 0 {
return (-x)
}
return x
}

View File

@@ -389,3 +389,18 @@ func ExampleLog() {
// 2.32
// 3
}
func ExampleAbs() {
result1 := Abs(-1)
result2 := Abs(-0.1)
result3 := Abs(float32(0.2))
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 0.1
// 0.2
}

View File

@@ -8,6 +8,8 @@ import (
)
func TestExponent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestExponent")
assert.Equal(int64(1), Exponent(10, 0))
@@ -16,6 +18,8 @@ func TestExponent(t *testing.T) {
}
func TestFibonacci(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFibonacci")
assert.Equal(0, Fibonacci(1, 1, 0))
@@ -25,6 +29,8 @@ func TestFibonacci(t *testing.T) {
}
func TestFactorial(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFactorial")
assert.Equal(uint(1), Factorial(0))
@@ -34,6 +40,8 @@ func TestFactorial(t *testing.T) {
}
func TestPercent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPercent")
assert.EqualValues(50, Percent(1, 2, 2))
@@ -42,6 +50,8 @@ func TestPercent(t *testing.T) {
}
func TestRoundToFloat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRoundToFloat")
assert.Equal(float64(0), RoundToFloat(0, 0))
@@ -53,6 +63,8 @@ func TestRoundToFloat(t *testing.T) {
}
func TestRoundToString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRoundToString")
assert.Equal("0", RoundToString(0, 0))
@@ -63,6 +75,8 @@ func TestRoundToString(t *testing.T) {
}
func TestTruncRound(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTruncRound")
assert.Equal(float64(0), TruncRound(0, 0))
@@ -74,6 +88,8 @@ func TestTruncRound(t *testing.T) {
}
func TestAverage(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAverage")
assert.Equal(0, Average(0, 0))
@@ -84,6 +100,8 @@ func TestAverage(t *testing.T) {
}
func TestSum(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSum")
assert.Equal(1, Sum(0, 1))
@@ -91,6 +109,8 @@ func TestSum(t *testing.T) {
}
func TestMax(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMax")
assert.Equal(0, Max(0, 0))
@@ -102,6 +122,8 @@ func TestMax(t *testing.T) {
}
func TestMaxBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "MaxBy")
res1 := MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
@@ -121,6 +143,8 @@ func TestMaxBy(t *testing.T) {
}
func TestMin(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMin")
assert.Equal(0, Min(0, 0))
@@ -129,6 +153,8 @@ func TestMin(t *testing.T) {
}
func TestMinBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMinBy")
res1 := MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
@@ -148,6 +174,8 @@ func TestMinBy(t *testing.T) {
}
func TestRange(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRange")
result1 := Range(1, 4)
@@ -164,6 +192,8 @@ func TestRange(t *testing.T) {
}
func TestRangeWithStep(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRangeWithStep")
result1 := RangeWithStep(1, 4, 1)
@@ -178,6 +208,8 @@ func TestRangeWithStep(t *testing.T) {
}
func TestAngleToRadian(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAngleToRadian")
result1 := AngleToRadian(45)
@@ -190,6 +222,8 @@ func TestAngleToRadian(t *testing.T) {
}
func TestRadianToAngle(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAngleToRadian")
result1 := RadianToAngle(math.Pi)
@@ -202,6 +236,8 @@ func TestRadianToAngle(t *testing.T) {
}
func TestPointDistance(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPointDistance")
result1 := PointDistance(1, 1, 4, 5)
@@ -210,6 +246,8 @@ func TestPointDistance(t *testing.T) {
}
func TestIsPrime(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsPrime")
assert.Equal(false, IsPrime(-1))
@@ -221,6 +259,8 @@ func TestIsPrime(t *testing.T) {
}
func TestGCD(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGCD")
assert.Equal(1, GCD(1, 1))
@@ -246,6 +286,8 @@ func TestGCD(t *testing.T) {
}
func TestLCM(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLCM")
assert.Equal(1, LCM(1))
@@ -259,6 +301,8 @@ func TestLCM(t *testing.T) {
}
func TestCos(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCos")
assert.EqualValues(1, Cos(0))
@@ -269,6 +313,8 @@ func TestCos(t *testing.T) {
}
func TestSin(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSin")
assert.EqualValues(0, Sin(0))
@@ -279,9 +325,25 @@ func TestSin(t *testing.T) {
}
func TestLog(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLog")
assert.EqualValues(3, Log(8, 2))
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
}
func TestAbs(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAbs")
assert.Equal(0, Abs(0))
assert.Equal(1, Abs(-1))
assert.Equal(0.1, Abs(-0.1))
assert.Equal(int64(1), Abs(int64(-1)))
assert.Equal(float32(1), Abs(float32(-1)))
}

View File

@@ -126,6 +126,8 @@ func TestHttpDelete(t *testing.T) {
}
func TestConvertMapToQueryString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestConvertMapToQueryString")
var m = map[string]any{
@@ -133,6 +135,7 @@ func TestConvertMapToQueryString(t *testing.T) {
"a": 1,
"b": 2,
}
assert.Equal("a=1&b=2&c=3", ConvertMapToQueryString(m))
}
@@ -163,6 +166,8 @@ func TestParseResponse(t *testing.T) {
}
func TestHttpClient_Get(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHttpClient_Get")
request := &HttpRequest{
@@ -218,6 +223,8 @@ func TestHttpClent_Post(t *testing.T) {
}
func TestStructToUrlValues(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStructToUrlValues")
type TodoQuery struct {

View File

@@ -9,6 +9,8 @@ import (
)
func TestGetInternalIp(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetInternalIp")
internalIp := GetInternalIp()
@@ -17,6 +19,8 @@ func TestGetInternalIp(t *testing.T) {
}
func TestGetRequestPublicIp(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGetPublicIpInfo")
ip := "36.112.24.10"
@@ -50,6 +54,8 @@ func TestGetRequestPublicIp(t *testing.T) {
// }
func TestIsPublicIP(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsPublicIP")
ips := []net.IP{
@@ -69,6 +75,8 @@ func TestIsPublicIP(t *testing.T) {
}
func TestIsInternalIP(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsInternalIP")
ips := []net.IP{
@@ -110,14 +118,9 @@ func TestEncodeUrl(t *testing.T) {
assert.Equal(expected, encodedUrl)
}
// func TestDownloadFile(t *testing.T) {
// assert := internal.NewAssert(t, "TestDownloadFile")
// err := DownloadFile("./lancet_logo.jpg", "https://picx.zhimg.com/v2-fc82a4199749de9cfb71e32e54f489d3_720w.jpg?source=172ae18b")
// assert.IsNil(err)
// }
func TestIsPingConnected(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsPingConnected")
// in github action env, this will fail
@@ -129,6 +132,8 @@ func TestIsPingConnected(t *testing.T) {
}
func TestTelnetConnected(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTelnetConnected")
result1 := IsTelnetConnected("bing.com", "80")

View File

@@ -7,19 +7,39 @@ package pointer
import "reflect"
// Of returns a pointer to the value `v`.
// Play: todo
// Play: https://go.dev/play/p/HFd70x4DrMj
func Of[T any](v T) *T {
return &v
}
// Unwrap returns the value from the pointer.
// Play: todo
// Play: https://go.dev/play/p/cgeu3g7cjWb
func Unwrap[T any](p *T) T {
return *p
}
// UnwarpOr returns the value from the pointer or fallback if the pointer is nil.
// Play: https://go.dev/play/p/mmNaLC38W8C
func UnwarpOr[T any](p *T, fallback T) T {
if p == nil {
return fallback
}
return *p
}
// UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
// Play: https://go.dev/play/p/ZnGIHf8_o4E
func UnwarpOrDefault[T any](p *T) T {
var v T
if p == nil {
return v
}
return *p
}
// ExtractPointer returns the underlying value by the given interface type
// Play: todo
// Play: https://go.dev/play/p/D7HFjeWU2ZP
func ExtractPointer(value any) any {
t := reflect.TypeOf(value)
v := reflect.ValueOf(value)

View File

@@ -29,6 +29,54 @@ func ExampleUnwrap() {
// abc
}
func ExampleUnwarpOr() {
a := 123
b := "abc"
var c *int
var d *string
result1 := UnwarpOr(&a, 456)
result2 := UnwarpOr(&b, "abc")
result3 := UnwarpOr(c, 456)
result4 := UnwarpOr(d, "def")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 456
// def
}
func ExampleUnwarpOrDefault() {
a := 123
b := "abc"
var c *int
var d *string
result1 := UnwarpOrDefault(&a)
result2 := UnwarpOrDefault(&b)
result3 := UnwarpOrDefault(c)
result4 := UnwarpOrDefault(d)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// 123
// abc
// 0
//
}
func ExampleExtractPointer() {
a := 1
b := &a

View File

@@ -7,6 +7,8 @@ import (
)
func TestOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOf")
result1 := Of(123)
@@ -17,6 +19,8 @@ func TestOf(t *testing.T) {
}
func TestUnwrap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnwrap")
a := 123
@@ -26,7 +30,43 @@ func TestUnwrap(t *testing.T) {
assert.Equal(b, Unwrap(&b))
}
func TestUnwarpOr(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnwarpOr")
a := 123
b := "abc"
var c *int
var d *string
assert.Equal(a, UnwarpOr(&a, 456))
assert.Equal(b, UnwarpOr(&b, "abc"))
assert.Equal(456, UnwarpOr(c, 456))
assert.Equal("def", UnwarpOr(d, "def"))
}
func TestUnwarpOrDefault(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnwarpOrDefault")
a := 123
b := "abc"
var c *int
var d *string
assert.Equal(a, UnwarpOrDefault(&a))
assert.Equal(b, UnwarpOrDefault(&b))
assert.Equal(0, UnwarpOrDefault(c))
assert.Equal("", UnwarpOrDefault(d))
}
func TestExtractPointer(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestExtractPointer")
a := 1

View File

@@ -9,6 +9,8 @@ import (
)
func TestResolve(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestResolve")
p := Resolve("abc")
@@ -18,6 +20,8 @@ func TestResolve(t *testing.T) {
}
func TestReject(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReject")
err := errors.New("error")
@@ -28,6 +32,8 @@ func TestReject(t *testing.T) {
}
func TestThen(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestThen")
p1 := New(func(resolve func(string), reject func(error)) {
@@ -48,6 +54,8 @@ func TestThen(t *testing.T) {
}
func TestPromise_Then(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPromise_Then")
p1 := New(func(resolve func(int), reject func(error)) {
@@ -68,6 +76,8 @@ func TestPromise_Then(t *testing.T) {
}
func TestCatch(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCatch")
p1 := New(func(resolve func(string), reject func(error)) {
@@ -93,6 +103,8 @@ func TestCatch(t *testing.T) {
}
func TestPromise_Catch(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPromise_Catch")
p1 := New(func(resolve func(string), reject func(error)) {
@@ -118,6 +130,8 @@ func TestPromise_Catch(t *testing.T) {
}
func TestAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPromise_All")
t.Run("AllPromisesFullfilled", func(_ *testing.T) {
@@ -180,7 +194,6 @@ func TestAll(t *testing.T) {
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}
@@ -227,7 +240,6 @@ func TestAny(t *testing.T) {
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}
@@ -275,7 +287,6 @@ func TestRace(t *testing.T) {
val, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
assert.Equal("", val)
})
@@ -296,7 +307,6 @@ func TestRace(t *testing.T) {
_, err := p.Await()
assert.IsNotNil(err)
// assert.Equal("error1", err.Error())
})
}

View File

@@ -116,7 +116,7 @@ func UUIdV4() (string, error) {
}
// RandUniqueIntSlice generate a slice of random int of length n that do not repeat.
// Play: todo
// Play: https://go.dev/play/p/uBkRSOz73Ec
func RandUniqueIntSlice(n, min, max int) []int {
if min > max {
return []int{}

View File

@@ -9,6 +9,8 @@ import (
)
func TestRandString(t *testing.T) {
t.Parallel()
pattern := `^[a-zA-Z]+$`
reg := regexp.MustCompile(pattern)
@@ -20,6 +22,8 @@ func TestRandString(t *testing.T) {
}
func TestRandUpper(t *testing.T) {
t.Parallel()
pattern := `^[A-Z]+$`
reg := regexp.MustCompile(pattern)
@@ -31,6 +35,8 @@ func TestRandUpper(t *testing.T) {
}
func TestRandLower(t *testing.T) {
t.Parallel()
pattern := `^[a-z]+$`
reg := regexp.MustCompile(pattern)
@@ -42,6 +48,8 @@ func TestRandLower(t *testing.T) {
}
func TestRandNumeral(t *testing.T) {
t.Parallel()
pattern := `^[0-9]+$`
reg := regexp.MustCompile(pattern)
@@ -53,6 +61,8 @@ func TestRandNumeral(t *testing.T) {
}
func TestRandNumeralOrLetter(t *testing.T) {
t.Parallel()
pattern := `^[0-9a-zA-Z]+$`
reg := regexp.MustCompile(pattern)
@@ -64,6 +74,8 @@ func TestRandNumeralOrLetter(t *testing.T) {
}
func TestRandInt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandInt")
r1 := RandInt(1, 10)
@@ -79,6 +91,8 @@ func TestRandInt(t *testing.T) {
}
func TestRandBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandBytes")
randBytes := RandBytes(4)
@@ -93,6 +107,8 @@ func TestRandBytes(t *testing.T) {
}
func TestUUIdV4(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUUIdV4")
uuid, err := UUIdV4()
@@ -105,6 +121,8 @@ func TestUUIdV4(t *testing.T) {
}
func TestRandUniqueIntSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandUniqueIntSlice")
r1 := RandUniqueIntSlice(5, 0, 9)

View File

@@ -10,6 +10,8 @@ import (
)
func TestRetryFailed(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRetryFailed")
var number int
@@ -25,6 +27,8 @@ func TestRetryFailed(t *testing.T) {
}
func TestRetrySucceeded(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRetrySucceeded")
var number int
@@ -43,6 +47,8 @@ func TestRetrySucceeded(t *testing.T) {
}
func TestSetRetryTimes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSetRetryTimes")
var number int
@@ -58,6 +64,8 @@ func TestSetRetryTimes(t *testing.T) {
}
func TestCancelRetry(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCancelRetry")
ctx, cancel := context.WithCancel(context.TODO())

View File

@@ -9,6 +9,7 @@ import (
"math/rand"
"reflect"
"sort"
"strings"
"time"
"golang.org/x/exp/constraints"
@@ -436,8 +437,8 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
// ForEach iterates over elements of slice and invokes function for each element.
// Play: https://go.dev/play/p/DrPaa4YsHRF
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
for i, v := range slice {
iteratee(i, v)
for i := 0; i < len(slice); i++ {
iteratee(i, slice[i])
}
}
@@ -445,8 +446,8 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
// when iteratee return false, will break the for each loop.
// Play: https://go.dev/play/p/qScs39f3D9W
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
for i, v := range slice {
if !iteratee(i, v) {
for i := 0; i < len(slice); i++ {
if !iteratee(i, slice[i]) {
break
}
}
@@ -457,8 +458,8 @@ func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
result := make([]U, len(slice), cap(slice))
for i, v := range slice {
result[i] = iteratee(i, v)
for i := 0; i < len(slice); i++ {
result[i] = iteratee(i, slice[i])
}
return result
@@ -1188,3 +1189,13 @@ func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
return result
}
// Join the slice item with specify separator.
// Play: https://go.dev/play/p/huKzqwNDD7V
func Join[T any](s []T, separator string) string {
str := Map(s, func(_ int, item T) string {
return fmt.Sprint(item)
})
return strings.Join(str, separator)
}

View File

@@ -1032,3 +1032,17 @@ func ExampleKeyBy() {
// Output:
// map[1:a 2:ab 3:abc]
}
func ExampleJoin() {
nums := []int{1, 2, 3, 4, 5}
result1 := Join(nums, ",")
result2 := Join(nums, "-")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1,2,3,4,5
// 1-2-3-4-5
}

View File

@@ -10,6 +10,8 @@ import (
)
func TestContain(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContain")
assert.Equal(true, Contain([]string{"a", "b", "c"}, "a"))
@@ -21,6 +23,8 @@ func TestContain(t *testing.T) {
}
func TestContainBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContainBy")
type foo struct {
@@ -43,6 +47,8 @@ func TestContainBy(t *testing.T) {
}
func TestContainSubSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContainSubSlice")
assert.Equal(true, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "a"}))
assert.Equal(false, ContainSubSlice([]string{"a", "a", "b", "c"}, []string{"a", "d"}))
@@ -51,6 +57,8 @@ func TestContainSubSlice(t *testing.T) {
}
func TestChunk(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestChunk")
arr := []string{"a", "b", "c", "d", "e"}
@@ -79,6 +87,8 @@ func TestChunk(t *testing.T) {
}
func TestCompact(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TesCompact")
assert.Equal([]int{}, Compact([]int{0}))
@@ -90,6 +100,8 @@ func TestCompact(t *testing.T) {
}
func TestConcat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "Concat")
assert.Equal([]int{1, 2, 3, 4, 5}, Concat([]int{1, 2, 3}, []int{4, 5}))
@@ -97,6 +109,8 @@ func TestConcat(t *testing.T) {
}
func TestEqual(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqual")
slice1 := []int{1, 2, 3}
@@ -115,6 +129,8 @@ func FuzzEqual(f *testing.F) {
}
func TestEqualWith(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqualWith")
slice1 := []int{1, 2, 3}
@@ -128,6 +144,8 @@ func TestEqualWith(t *testing.T) {
}
func TestEvery(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEvery")
nums := []int{1, 2, 3, 5}
@@ -139,6 +157,8 @@ func TestEvery(t *testing.T) {
}
func TestNone(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestNone")
nums := []int{1, 2, 3, 5}
@@ -150,6 +170,8 @@ func TestNone(t *testing.T) {
}
func TestSome(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSome")
nums := []int{1, 2, 3, 5}
@@ -161,6 +183,8 @@ func TestSome(t *testing.T) {
}
func TestFilter(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilter")
nums := []int{1, 2, 3, 4, 5}
@@ -193,6 +217,8 @@ func TestFilter(t *testing.T) {
}
func TestGroupBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestGroupBy")
nums := []int{1, 2, 3, 4, 5, 6}
@@ -206,6 +232,8 @@ func TestGroupBy(t *testing.T) {
}
func TestGroupWith(t *testing.T) {
t.Parallel()
nums := []float64{6.1, 4.2, 6.3}
floor := func(num float64) float64 {
return math.Floor(num)
@@ -220,6 +248,8 @@ func TestGroupWith(t *testing.T) {
}
func TestCount(t *testing.T) {
t.Parallel()
numbers := []int{1, 2, 3, 3, 5, 6}
assert := internal.NewAssert(t, "TestCountBy")
@@ -229,6 +259,8 @@ func TestCount(t *testing.T) {
}
func TestCountBy(t *testing.T) {
t.Parallel()
nums := []int{1, 2, 3, 4, 5, 6}
evenFunc := func(i, num int) bool {
return (num % 2) == 0
@@ -239,6 +271,8 @@ func TestCountBy(t *testing.T) {
}
func TestFind(t *testing.T) {
t.Parallel()
nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool {
return num%2 == 0
@@ -251,6 +285,8 @@ func TestFind(t *testing.T) {
}
func TestFindBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFindBy")
nums := []int{1, 2, 3, 4, 5}
@@ -269,6 +305,8 @@ func TestFindBy(t *testing.T) {
}
func TestFindLastBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFindLastBy")
nums := []int{1, 2, 3, 4, 5}
@@ -289,6 +327,8 @@ func TestFindLastBy(t *testing.T) {
}
func TestFindLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFindLast")
nums := []int{1, 2, 3, 4, 5}
@@ -304,6 +344,8 @@ func TestFindLast(t *testing.T) {
}
func TestFindFoundNothing(t *testing.T) {
t.Parallel()
nums := []int{1, 1, 1, 1, 1, 1}
findFunc := func(i, num int) bool {
return num > 1
@@ -315,6 +357,8 @@ func TestFindFoundNothing(t *testing.T) {
}
func TestFlatten(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFlatten")
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
@@ -324,6 +368,8 @@ func TestFlatten(t *testing.T) {
}
func TestFlattenDeep(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFlattenDeep")
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
@@ -333,6 +379,8 @@ func TestFlattenDeep(t *testing.T) {
}
func TestForEach(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
numbers := []int{1, 2, 3, 4, 5}
@@ -348,6 +396,8 @@ func TestForEach(t *testing.T) {
}
func TestForEachWithBreak(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEach")
numbers := []int{1, 2, 3, 4, 5}
@@ -366,6 +416,8 @@ func TestForEachWithBreak(t *testing.T) {
}
func TestMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMap")
nums := []int{1, 2, 3, 4}
@@ -398,6 +450,8 @@ func TestMap(t *testing.T) {
}
func TestFilterMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilterMap")
nums := []int{1, 2, 3, 4, 5}
@@ -415,6 +469,8 @@ func TestFilterMap(t *testing.T) {
}
func TestFlatMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFlatMap")
nums := []int{1, 2, 3, 4}
@@ -428,6 +484,8 @@ func TestFlatMap(t *testing.T) {
}
func TestReduce(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReduce")
cases := [][]int{
@@ -448,6 +506,8 @@ func TestReduce(t *testing.T) {
}
func TestReduceBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReduceBy")
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
@@ -464,6 +524,8 @@ func TestReduceBy(t *testing.T) {
}
func TestReduceRight(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReduceRight")
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
@@ -474,6 +536,8 @@ func TestReduceRight(t *testing.T) {
}
func TestIntSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntSlice")
var nums []any
@@ -483,6 +547,8 @@ func TestIntSlice(t *testing.T) {
}
func TestStringSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStringSlice")
var strs []any
@@ -492,6 +558,8 @@ func TestStringSlice(t *testing.T) {
}
func TestInterfaceSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInterfaceSlice")
strs := []string{"a", "b", "c"}
@@ -501,6 +569,8 @@ func TestInterfaceSlice(t *testing.T) {
}
func TestDeleteAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDeleteAt")
assert.Equal([]string{"a", "b", "c"}, DeleteAt([]string{"a", "b", "c"}, -1))
@@ -518,6 +588,8 @@ func TestDeleteAt(t *testing.T) {
}
func TestDrop(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDrop")
assert.Equal([]int{}, Drop([]int{}, 0))
@@ -533,6 +605,8 @@ func TestDrop(t *testing.T) {
}
func TestDropRight(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDropRight")
assert.Equal([]int{}, DropRight([]int{}, 0))
@@ -548,6 +622,8 @@ func TestDropRight(t *testing.T) {
}
func TestDropWhile(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDropWhile")
numbers := []int{1, 2, 3, 4, 5}
@@ -569,6 +645,8 @@ func TestDropWhile(t *testing.T) {
}
func TestDropRightWhile(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDropRightWhile")
numbers := []int{1, 2, 3, 4, 5}
@@ -590,6 +668,8 @@ func TestDropRightWhile(t *testing.T) {
}
func TestInsertAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestInsertAt")
strs := []string{"a", "b", "c"}
@@ -604,6 +684,8 @@ func TestInsertAt(t *testing.T) {
}
func TestUpdateAt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpdateAt")
assert.Equal([]string{"a", "b", "c"}, UpdateAt([]string{"a", "b", "c"}, -1, "1"))
@@ -613,6 +695,8 @@ func TestUpdateAt(t *testing.T) {
}
func TestUnique(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnique")
assert.Equal([]int{1, 2, 3}, Unique([]int{1, 2, 2, 3}))
@@ -620,6 +704,8 @@ func TestUnique(t *testing.T) {
}
func TestUniqueBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUniqueBy")
actual := UniqueBy([]int{1, 2, 3, 4, 5, 6}, func(val int) int {
@@ -629,6 +715,8 @@ func TestUniqueBy(t *testing.T) {
}
func TestUnion(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnion")
s1 := []int{1, 3, 4, 6}
@@ -641,6 +729,8 @@ func TestUnion(t *testing.T) {
}
func TestUnionBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnionBy")
testFunc := func(i int) int {
@@ -652,6 +742,8 @@ func TestUnionBy(t *testing.T) {
}
func TestMerge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMerge")
s1 := []int{1, 2, 3, 4}
@@ -664,6 +756,8 @@ func TestMerge(t *testing.T) {
}
func TestIntersection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIntersection")
s1 := []int{1, 2, 2, 3}
@@ -690,6 +784,8 @@ func TestIntersection(t *testing.T) {
}
func TestSymmetricDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSymmetricDifference")
s1 := []int{1, 2, 3}
@@ -702,6 +798,8 @@ func TestSymmetricDifference(t *testing.T) {
}
func TestReverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReverse")
s1 := []int{1, 2, 3, 4, 5}
@@ -714,6 +812,8 @@ func TestReverse(t *testing.T) {
}
func TestDifference(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifference")
s1 := []int{1, 2, 3, 4, 5}
@@ -723,6 +823,8 @@ func TestDifference(t *testing.T) {
}
func TestDifferenceWith(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifferenceWith")
s1 := []int{1, 2, 3, 4, 5}
@@ -735,6 +837,8 @@ func TestDifferenceWith(t *testing.T) {
}
func TestDifferenceBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestDifferenceBy")
s1 := []int{1, 2, 3, 4, 5} // after add one: 2 3 4 5 6
@@ -747,6 +851,8 @@ func TestDifferenceBy(t *testing.T) {
}
func TestIsAscending(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsAscending")
assert.Equal(true, IsAscending([]int{1, 2, 3, 4, 5}))
@@ -755,6 +861,8 @@ func TestIsAscending(t *testing.T) {
}
func TestIsDescending(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsDescending")
assert.Equal(true, IsDescending([]int{5, 4, 3, 2, 1}))
@@ -763,6 +871,8 @@ func TestIsDescending(t *testing.T) {
}
func TestIsSorted(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsSorted")
assert.Equal(true, IsSorted([]int{5, 4, 3, 2, 1}))
@@ -771,6 +881,8 @@ func TestIsSorted(t *testing.T) {
}
func TestIsSortedByKey(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsSortedByKey")
assert.Equal(true, IsSortedByKey([]string{"a", "ab", "abc"}, func(s string) int {
@@ -787,6 +899,8 @@ func TestIsSortedByKey(t *testing.T) {
}
func TestSort(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSort")
numbers := []int{1, 4, 3, 2, 5}
@@ -807,6 +921,8 @@ func TestSort(t *testing.T) {
}
func TestSortBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSortBy")
numbers := []int{1, 4, 3, 2, 5}
@@ -836,6 +952,8 @@ func TestSortBy(t *testing.T) {
}
func TestSortByFielDesc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSortByFielDesc")
type student struct {
@@ -862,6 +980,8 @@ func TestSortByFielDesc(t *testing.T) {
}
func TestSortByFieldAsc(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSortByFieldAsc")
type student struct {
@@ -888,12 +1008,16 @@ func TestSortByFieldAsc(t *testing.T) {
}
func TestWithout(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestWithout")
assert.Equal([]int{3, 4, 5}, Without([]int{1, 2, 3, 4, 5}, 1, 2))
assert.Equal([]int{1, 2, 3, 4, 5}, Without([]int{1, 2, 3, 4, 5}))
}
func TestShuffle(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestShuffle")
numbers := []int{1, 2, 3, 4, 5}
@@ -903,6 +1027,8 @@ func TestShuffle(t *testing.T) {
}
func TestIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOf")
arr := []string{"a", "a", "b", "c"}
@@ -942,6 +1068,8 @@ func TestIndexOf(t *testing.T) {
}
func TestLastIndexOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLastIndexOf")
arr := []string{"a", "b", "b", "c"}
@@ -951,6 +1079,8 @@ func TestLastIndexOf(t *testing.T) {
}
func TestToSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToSlice")
str1 := "a"
@@ -960,6 +1090,8 @@ func TestToSlice(t *testing.T) {
}
func TestToSlicePointer(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestToSlicePointer")
str1 := "a"
@@ -969,6 +1101,8 @@ func TestToSlicePointer(t *testing.T) {
}
func TestAppendIfAbsent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAppendIfAbsent")
str1 := []string{"a", "b"}
@@ -977,6 +1111,8 @@ func TestAppendIfAbsent(t *testing.T) {
}
func TestReplace(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReplace")
strs := []string{"a", "b", "a", "c", "d", "a"}
@@ -995,6 +1131,8 @@ func TestReplace(t *testing.T) {
}
func TestReplaceAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReplaceAll")
strs := []string{"a", "b", "a", "c", "d", "a"}
@@ -1004,6 +1142,8 @@ func TestReplaceAll(t *testing.T) {
}
func TestKeyBy(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestKeyBy")
result := KeyBy([]string{"a", "ab", "abc"}, func(str string) int {
@@ -1014,8 +1154,24 @@ func TestKeyBy(t *testing.T) {
}
func TestRepeat(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRepeat")
assert.Equal([]string{}, Repeat("a", 0))
assert.Equal([]string{"a", "a", "a", "a", "a", "a"}, Repeat("a", 6))
}
func TestJoin(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestJoin")
nums := []int{1, 2, 3, 4, 5}
result1 := Join(nums, ",")
result2 := Join(nums, "-")
assert.Equal("1,2,3,4,5", result1)
assert.Equal("1-2-3-4-5", result2)
}

View File

@@ -8,6 +8,8 @@ import (
)
func TestOf(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromSlice")
stream := Of(1, 2, 3)
@@ -15,6 +17,8 @@ func TestOf(t *testing.T) {
}
func TestGenerate(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromSlice")
n := 0
@@ -33,14 +37,17 @@ func TestGenerate(t *testing.T) {
}
func TestFromSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromSlice")
stream := FromSlice([]int{1, 2, 3})
assert.Equal([]int{1, 2, 3}, stream.ToSlice())
}
func TestFromChannel(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromChannel")
ch := make(chan int)
@@ -57,6 +64,8 @@ func TestFromChannel(t *testing.T) {
}
func TestFromRange(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFromRange")
s1 := FromRange(1, 5, 1)
@@ -67,6 +76,8 @@ func TestFromRange(t *testing.T) {
}
func TestStream_Distinct(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStream_Distinct")
nums := FromSlice([]int{1, 2, 2, 3, 3, 3})
@@ -99,6 +110,8 @@ func TestStream_Distinct(t *testing.T) {
}
func TestStream_Filter(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStream_Filter")
stream := FromSlice([]int{1, 2, 3, 4, 5})

View File

@@ -1,12 +1,15 @@
package structs
import (
"github.com/duke-git/lancet/v2/internal"
"reflect"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestField_Tag(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_Tag")
type Parent struct {
@@ -17,11 +20,14 @@ func TestField_Tag(t *testing.T) {
s := New(p1)
n, _ := s.Field("Name")
tag := n.Tag()
assert.Equal("name", tag.Name)
assert.Equal(true, tag.HasOption("omitempty"))
}
func TestField_Value(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_Value")
type Parent struct {
@@ -36,7 +42,10 @@ func TestField_Value(t *testing.T) {
}
func TestField_IsEmbedded(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_IsEmbedded")
type Parent struct {
Name string
}
@@ -51,11 +60,14 @@ func TestField_IsEmbedded(t *testing.T) {
s := New(c1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal(true, n.IsEmbedded())
assert.Equal(false, a.IsEmbedded())
}
func TestField_IsExported(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_IsEmbedded")
type Parent struct {
@@ -66,11 +78,14 @@ func TestField_IsExported(t *testing.T) {
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("age")
assert.Equal(true, n.IsExported())
assert.Equal(false, a.IsExported())
}
func TestField_IsZero(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_IsZero")
type Parent struct {
@@ -81,11 +96,14 @@ func TestField_IsZero(t *testing.T) {
s := New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
assert.Equal(true, n.IsZero())
assert.Equal(false, a.IsZero())
}
func TestField_Name(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_Name")
type Parent struct {
@@ -102,6 +120,8 @@ func TestField_Name(t *testing.T) {
}
func TestField_Kind(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_Kind")
type Parent struct {
@@ -118,6 +138,8 @@ func TestField_Kind(t *testing.T) {
}
func TestField_IsSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_IsSlice")
type Parent struct {
@@ -133,6 +155,8 @@ func TestField_IsSlice(t *testing.T) {
}
func TestField_MapValue(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestField_MapValue")
t.Run("nested struct", func(t *testing.T) {

View File

@@ -8,8 +8,9 @@ import (
)
func TestStruct_ToMap(t *testing.T) {
assert := internal.NewAssert(t, "TestStruct_ToMap")
t.Parallel()
assert := internal.NewAssert(t, "TestStruct_ToMap")
t.Run("invalid struct", func(t *testing.T) {
m, _ := ToMap(1)
var expected map[string]any
@@ -65,6 +66,8 @@ func TestStruct_ToMap(t *testing.T) {
}
func TestStruct_Fields(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStruct_Fields")
type Parent struct {
@@ -91,6 +94,8 @@ func TestStruct_Fields(t *testing.T) {
}
func TestStruct_Field(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStruct_Field")
type Parent struct {
@@ -109,6 +114,7 @@ func TestStruct_Field(t *testing.T) {
s := New(p1)
a, ok := s.Field("A")
assert.Equal(true, ok)
assert.Equal(reflect.String, a.Kind())
assert.Equal("1", a.Value())
@@ -118,6 +124,8 @@ func TestStruct_Field(t *testing.T) {
}
func TestStruct_IsStruct(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStruct_Field")
type Test1 struct{}

View File

@@ -561,7 +561,7 @@ var (
// RemoveWhiteSpace remove whitespace characters from a string.
// when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.
// Play: todo
// Play: https://go.dev/play/p/HzLC9vsTwkf
func RemoveWhiteSpace(str string, repalceAll bool) string {
if repalceAll && str != "" {
return strings.Join(strings.Fields(str), "")

View File

@@ -8,6 +8,8 @@ import (
)
func TestCamelCase(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCamelCase")
cases := map[string]string{
@@ -27,6 +29,8 @@ func TestCamelCase(t *testing.T) {
}
func TestCapitalize(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestCapitalize")
cases := map[string]string{
@@ -46,6 +50,8 @@ func TestCapitalize(t *testing.T) {
}
func TestKebabCase(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestKebabCase")
cases := map[string]string{
@@ -69,6 +75,8 @@ func TestKebabCase(t *testing.T) {
}
func TestUpperKebabCase(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpperKebabCase")
cases := map[string]string{
@@ -92,6 +100,8 @@ func TestUpperKebabCase(t *testing.T) {
}
func TestSnakeCase(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSnakeCase")
cases := map[string]string{
@@ -115,6 +125,8 @@ func TestSnakeCase(t *testing.T) {
}
func TestUpperSnakeCase(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUpperSnakeCase")
cases := map[string]string{
@@ -138,6 +150,8 @@ func TestUpperSnakeCase(t *testing.T) {
}
func TestUpperFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLowerFirst")
cases := map[string]string{
@@ -154,6 +168,8 @@ func TestUpperFirst(t *testing.T) {
}
func TestLowerFirst(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestLowerFirst")
cases := map[string]string{
@@ -170,6 +186,8 @@ func TestLowerFirst(t *testing.T) {
}
func TestPad(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPad")
assert.Equal("a ", Pad("a", 2, ""))
@@ -192,6 +210,8 @@ func TestPadEnd(t *testing.T) {
}
func TestPadStart(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestPadStart")
assert.Equal("a", PadStart("a", 1, "b"))
@@ -204,6 +224,8 @@ func TestPadStart(t *testing.T) {
}
func TestBefore(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBefore")
assert.Equal("lancet", Before("lancet", ""))
@@ -213,6 +235,8 @@ func TestBefore(t *testing.T) {
}
func TestBeforeLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBeforeLast")
assert.Equal("lancet", BeforeLast("lancet", ""))
@@ -223,6 +247,8 @@ func TestBeforeLast(t *testing.T) {
}
func TestAfter(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAfter")
assert.Equal("lancet", After("lancet", ""))
@@ -232,6 +258,8 @@ func TestAfter(t *testing.T) {
}
func TestAfterLast(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAfterLast")
assert.Equal("lancet", AfterLast("lancet", ""))
@@ -243,6 +271,8 @@ func TestAfterLast(t *testing.T) {
}
func TestIsString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsString")
assert.Equal(true, IsString("lancet"))
@@ -253,6 +283,8 @@ func TestIsString(t *testing.T) {
}
func TestReverse(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReverse")
assert.Equal("cba", Reverse("abc"))
@@ -260,6 +292,8 @@ func TestReverse(t *testing.T) {
}
func TestWrap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestWrap")
assert.Equal("ab", Wrap("ab", ""))
@@ -270,6 +304,8 @@ func TestWrap(t *testing.T) {
}
func TestUnwrap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnwrap")
assert.Equal("", Unwrap("", "*"))
@@ -288,6 +324,8 @@ func TestUnwrap(t *testing.T) {
}
func TestSplitEx(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSplitEx")
assert.Equal([]string{}, SplitEx(" a b c ", "", true))
@@ -300,6 +338,8 @@ func TestSplitEx(t *testing.T) {
}
func TestSubstring(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSubstring")
assert.Equal("bcd", Substring("abcde", 1, 3))
@@ -311,6 +351,8 @@ func TestSubstring(t *testing.T) {
}
func TestSplitWords(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSplitWords")
cases := map[string][]string{
@@ -327,6 +369,8 @@ func TestSplitWords(t *testing.T) {
}
func TestWordCount(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSplitWords")
cases := map[string]int{
@@ -343,6 +387,8 @@ func TestWordCount(t *testing.T) {
}
func TestRemoveNonPrintable(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRemoveNonPrintable")
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
@@ -350,47 +396,67 @@ func TestRemoveNonPrintable(t *testing.T) {
}
func TestStringToBytes(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestStringToBytes")
str := "abc"
bytes := StringToBytes(str)
assert.Equal(reflect.DeepEqual(bytes, []byte{'a', 'b', 'c'}), true)
}
func TestBytesToString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBytesToString")
bytes := []byte{'a', 'b', 'c'}
str := BytesToString(bytes)
assert.Equal(str == "abc", true)
}
func TestIsBlank(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIsBlank")
assert.Equal(IsBlank(""), true)
assert.Equal(IsBlank("\t\v\f\n"), true)
assert.Equal(IsBlank(" 中文"), false)
}
func TestHasPrefixAny(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHasPrefixAny")
str := "foo bar"
prefixes := []string{"fo", "xyz", "hello"}
notMatches := []string{"oom", "world"}
assert.Equal(HasPrefixAny(str, prefixes), true)
assert.Equal(HasPrefixAny(str, notMatches), false)
}
func TestHasSuffixAny(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestHasSuffixAny")
str := "foo bar"
suffixes := []string{"bar", "xyz", "hello"}
notMatches := []string{"oom", "world"}
assert.Equal(HasSuffixAny(str, suffixes), true)
assert.Equal(HasSuffixAny(str, notMatches), false)
}
func TestIndexOffset(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestIndexOffset")
str := "foo bar hello world"
assert.Equal(IndexOffset(str, "o", 5), 12)
assert.Equal(IndexOffset(str, "o", 0), 1)
assert.Equal(IndexOffset(str, "d", len(str)-1), len(str)-1)
@@ -399,6 +465,8 @@ func TestIndexOffset(t *testing.T) {
}
func TestReplaceWithMap(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestReplaceWithMap")
str := "ac ab ab ac"
@@ -412,6 +480,8 @@ func TestReplaceWithMap(t *testing.T) {
}
func TestTrim(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTrim")
str1 := "$ ab cd $ "
@@ -422,6 +492,8 @@ func TestTrim(t *testing.T) {
}
func TestSplitAndTrim(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTrim")
str := " a,b, c,d,$1 "
@@ -434,6 +506,8 @@ func TestSplitAndTrim(t *testing.T) {
}
func TestHideString(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTrim")
str := "13242658976"
@@ -452,6 +526,8 @@ func TestHideString(t *testing.T) {
}
func TestContainsAll(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContainsAll")
assert.Equal(true, ContainsAll("hello world", []string{"hello", "world"}))
@@ -460,6 +536,8 @@ func TestContainsAll(t *testing.T) {
}
func TestContainsAny(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestContainsAny")
assert.Equal(true, ContainsAny("hello world", []string{"hello", "world"}))

View File

@@ -8,6 +8,8 @@ import (
)
func TestOsDetection(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOsJudgment")
osType, _, _ := ExecCommand("echo $OSTYPE")
@@ -20,6 +22,8 @@ func TestOsDetection(t *testing.T) {
}
func TestOsEnvOperation(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestOsEnvOperation")
envNotExist := GetOsEnv("foo")
@@ -44,6 +48,8 @@ func TestOsEnvOperation(t *testing.T) {
}
func TestExecCommand(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestExecCommand")
// linux or mac
@@ -79,6 +85,8 @@ func TestExecCommand(t *testing.T) {
// }
func TestGetOsBits(t *testing.T) {
t.Parallel()
osBits := GetOsBits()
switch osBits {
case 32, 64:

641
tuple/tuple.go Normal file
View File

@@ -0,0 +1,641 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package tuple implements tuple data type and some operations on it.
package tuple
import "github.com/duke-git/lancet/v2/mathutil"
// Tuple2 represents a 2 elemnets tuple
type Tuple2[A any, B any] struct {
FieldA A
FieldB B
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/0fD1qfCVwjm
func (t Tuple2[A, B]) Unbox() (A, B) {
return t.FieldA, t.FieldB
}
// NewTuple2 creates a 2 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/3sHVqBQpLYN
func NewTuple2[A any, B any](a A, b B) Tuple2[A, B] {
return Tuple2[A, B]{FieldA: a, FieldB: b}
}
// Zip2 create a slice of Tuple2, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/4ncWJJ77Xio
func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B] {
size := mathutil.Max(len(a), len(b))
tuples := make([]Tuple2[A, B], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
tuples[i] = Tuple2[A, B]{FieldA: v1, FieldB: v2}
}
return tuples
}
// Unzip2 creates a group of slice from a slice of Tuple2.
// Play: https://go.dev/play/p/KBecr60feXb
func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
}
return r1, r2
}
// Tuple3 represents a 3 elemnets tuple
type Tuple3[A any, B any, C any] struct {
FieldA A
FieldB B
FieldC C
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/YojLy-id1BS
func (t Tuple3[A, B, C]) Unbox() (A, B, C) {
return t.FieldA, t.FieldB, t.FieldC
}
// NewTuple3 creates a 3 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/FtH2sdCLlCf
func NewTuple3[A any, B any, C any](a A, b B, c C) Tuple3[A, B, C] {
return Tuple3[A, B, C]{FieldA: a, FieldB: b, FieldC: c}
}
// Zip3 create a slice of Tuple3, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/97NgmsTILfu
func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C] {
size := mathutil.Max(len(a), len(b), len(c))
tuples := make([]Tuple3[A, B, C], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
tuples[i] = Tuple3[A, B, C]{FieldA: v1, FieldB: v2, FieldC: v3}
}
return tuples
}
// Unzip3 creates a group of slice from a slice of Tuple3.
// Play: https://go.dev/play/p/bba4cpAa7KO
func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
}
return r1, r2, r3
}
// Tuple4 represents a 4 elemnets tuple
type Tuple4[A any, B any, C any, D any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/ACj9YuACGgW
func (t Tuple4[A, B, C, D]) Unbox() (A, B, C, D) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD
}
// NewTuple4 creates a 4 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/D2EqDz096tk
func NewTuple4[A any, B any, C any, D any](a A, b B, c C, d D) Tuple4[A, B, C, D] {
return Tuple4[A, B, C, D]{FieldA: a, FieldB: b, FieldC: c, FieldD: d}
}
// Zip4 create a slice of Tuple4, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/PEmTYVK5hL4
func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, C, D] {
size := mathutil.Max(len(a), len(b), len(c), len(d))
tuples := make([]Tuple4[A, B, C, D], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
v4, _ := getByIndex(d, i)
tuples[i] = Tuple4[A, B, C, D]{FieldA: v1, FieldB: v2, FieldC: v3, FieldD: v4}
}
return tuples
}
// Unzip4 creates a group of slice from a slice of Tuple4.
// Play: https://go.dev/play/p/rb8z4gyYSRN
func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, []C, []D) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
}
return r1, r2, r3, r4
}
// Tuple5 represents a 5 elemnets tuple
type Tuple5[A any, B any, C any, D any, E any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/GyIyZHjCvoS
func (t Tuple5[A, B, C, D, E]) Unbox() (A, B, C, D, E) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE
}
// NewTuple5 creates a 5 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/2WndmVxPg-r
func NewTuple5[A any, B any, C any, D any, E any](a A, b B, c C, d D, e E) Tuple5[A, B, C, D, E] {
return Tuple5[A, B, C, D, E]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e}
}
// Zip5 create a slice of Tuple5, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/fCAAJLMfBIP
func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) []Tuple5[A, B, C, D, E] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e))
tuples := make([]Tuple5[A, B, C, D, E], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
v4, _ := getByIndex(d, i)
v5, _ := getByIndex(e, i)
tuples[i] = Tuple5[A, B, C, D, E]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5}
}
return tuples
}
// Unzip5 creates a group of slice from a slice of Tuple5.
// Play: https://go.dev/play/p/gyl6vKfhqPb
func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ([]A, []B, []C, []D, []E) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
}
return r1, r2, r3, r4, r5
}
// Tuple6 represents a 6 elemnets tuple
type Tuple6[A any, B any, C any, D any, E any, F any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
FieldF F
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/FjIHV7lpxmW
func (t Tuple6[A, B, C, D, E, F]) Unbox() (A, B, C, D, E, F) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF
}
// NewTuple6 creates a 6 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/VjqcCwEJZbs
func NewTuple6[A any, B any, C any, D any, E any, F any](a A, b B, c C, d D, e E, f F) Tuple6[A, B, C, D, E, F] {
return Tuple6[A, B, C, D, E, F]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f}
}
// Zip6 create a slice of Tuple6, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/oWPrnUYuFHo
func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, e []E, f []F) []Tuple6[A, B, C, D, E, F] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f))
tuples := make([]Tuple6[A, B, C, D, E, F], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
v4, _ := getByIndex(d, i)
v5, _ := getByIndex(e, i)
v6, _ := getByIndex(f, i)
tuples[i] = Tuple6[A, B, C, D, E, F]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5, FieldF: v6}
}
return tuples
}
// Unzip6 creates a group of slice from a slice of Tuple6.
// Play: https://go.dev/play/p/l41XFqCyh5E
func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D, E, F]) ([]A, []B, []C, []D, []E, []F) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
r6 := make([]F, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
r6[i] = t.FieldF
}
return r1, r2, r3, r4, r5, r6
}
// Tuple7 represents a 7 elemnets tuple
type Tuple7[A any, B any, C any, D any, E any, F any, G any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
FieldF F
FieldG G
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/R9I8qeDk0zs
func (t Tuple7[A, B, C, D, E, F, G]) Unbox() (A, B, C, D, E, F, G) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG
}
// NewTuple7 creates a 7 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/dzAgv_Ezub9
func NewTuple7[A any, B any, C any, D any, E any, F any, G any](a A, b B, c C, d D, e E, f F, g G) Tuple7[A, B, C, D, E, F, G] {
return Tuple7[A, B, C, D, E, F, G]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g}
}
// Zip7 create a slice of Tuple7, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/WUJuo897Egf
func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, d []D, e []E, f []F, g []G) []Tuple7[A, B, C, D, E, F, G] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g))
tuples := make([]Tuple7[A, B, C, D, E, F, G], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
v4, _ := getByIndex(d, i)
v5, _ := getByIndex(e, i)
v6, _ := getByIndex(f, i)
v7, _ := getByIndex(g, i)
tuples[i] = Tuple7[A, B, C, D, E, F, G]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5, FieldF: v6,
FieldG: v7}
}
return tuples
}
// Unzip7 creates a group of slice from a slice of Tuple7.
// Play: https://go.dev/play/p/hws_P1Fr2j3
func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, B, C, D, E, F, G]) ([]A, []B, []C, []D, []E, []F, []G) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
r6 := make([]F, size)
r7 := make([]G, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
r6[i] = t.FieldF
r7[i] = t.FieldG
}
return r1, r2, r3, r4, r5, r6, r7
}
// Tuple8 represents a 8 elemnets tuple
type Tuple8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
FieldF F
FieldG G
FieldH H
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/PRxLBBb4SMl
func (t Tuple8[A, B, C, D, E, F, G, H]) Unbox() (A, B, C, D, E, F, G, H) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH
}
// NewTuple8 creates a 8 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/YA9S0rz3dRz
func NewTuple8[A any, B any, C any, D any, E any, F any, G any, H any](a A, b B, c C, d D, e E, f F, g G, h H) Tuple8[A, B, C, D, E, F, G, H] {
return Tuple8[A, B, C, D, E, F, G, H]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h}
}
// Zip8 create a slice of Tuple8, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/8V9jWkuJfaQ
func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H) []Tuple8[A, B, C, D, E, F, G, H] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h))
tuples := make([]Tuple8[A, B, C, D, E, F, G, H], size)
for i := 0; i < size; i++ {
v1, _ := getByIndex(a, i)
v2, _ := getByIndex(b, i)
v3, _ := getByIndex(c, i)
v4, _ := getByIndex(d, i)
v5, _ := getByIndex(e, i)
v6, _ := getByIndex(f, i)
v7, _ := getByIndex(g, i)
v8, _ := getByIndex(h, i)
tuples[i] = Tuple8[A, B, C, D, E, F, G, H]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5, FieldF: v6,
FieldG: v7, FieldH: v8}
}
return tuples
}
// Unzip8 creates a group of slice from a slice of Tuple8.
// Play: https://go.dev/play/p/1SndOwGsZB4
func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tuple8[A, B, C, D, E, F, G, H]) ([]A, []B, []C, []D, []E, []F, []G, []H) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
r6 := make([]F, size)
r7 := make([]G, size)
r8 := make([]H, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
r6[i] = t.FieldF
r7[i] = t.FieldG
r8[i] = t.FieldH
}
return r1, r2, r3, r4, r5, r6, r7, r8
}
// Tuple9 represents a 9 elemnets tuple
type Tuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
FieldF F
FieldG G
FieldH H
FieldI I
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/oFJFGTAuOa8
func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unbox() (A, B, C, D, E, F, G, H, I) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI
}
// NewTuple9 creates a 9 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/yS2NGGtZpQr
func NewTuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a A, b B, c C, d D, e E, f F, g G, h H, i I) Tuple9[A, B, C, D, E, F, G, H, I] {
return Tuple9[A, B, C, D, E, F, G, H, I]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h, FieldI: i}
}
// Zip9 create a slice of Tuple9, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/cgsL15QYnfz
func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I) []Tuple9[A, B, C, D, E, F, G, H, I] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i))
tuples := make([]Tuple9[A, B, C, D, E, F, G, H, I], size)
for idx := 0; idx < size; idx++ {
v1, _ := getByIndex(a, idx)
v2, _ := getByIndex(b, idx)
v3, _ := getByIndex(c, idx)
v4, _ := getByIndex(d, idx)
v5, _ := getByIndex(e, idx)
v6, _ := getByIndex(f, idx)
v7, _ := getByIndex(g, idx)
v8, _ := getByIndex(h, idx)
v9, _ := getByIndex(i, idx)
tuples[idx] = Tuple9[A, B, C, D, E, F, G, H, I]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5, FieldF: v6,
FieldG: v7, FieldH: v8, FieldI: v9}
}
return tuples
}
// Unzip9 creates a group of slice from a slice of Tuple9.
// Play: https://go.dev/play/p/91-BU_KURSA
func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuples []Tuple9[A, B, C, D, E, F, G, H, I]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
r6 := make([]F, size)
r7 := make([]G, size)
r8 := make([]H, size)
r9 := make([]I, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
r6[i] = t.FieldF
r7[i] = t.FieldG
r8[i] = t.FieldH
r9[i] = t.FieldI
}
return r1, r2, r3, r4, r5, r6, r7, r8, r9
}
// Tuple10 represents a 10 elemnets tuple
type Tuple10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any] struct {
FieldA A
FieldB B
FieldC C
FieldD D
FieldE E
FieldF F
FieldG G
FieldH H
FieldI I
FieldJ J
}
// Unbox returns values in tuple.
// Play: https://go.dev/play/p/qfyx3x_X0Cu
func (t Tuple10[A, B, C, D, E, F, G, H, I, J]) Unbox() (A, B, C, D, E, F, G, H, I, J) {
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI, t.FieldJ
}
// NewTuple10 creates a 10 elemnets tuple from a list of values.
// Play: https://go.dev/play/p/799qqZg0hUv
func NewTuple10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](a A, b B, c C, d D, e E, f F, g G, h H, i I, j J) Tuple10[A, B, C, D, E, F, G, H, I, J] {
return Tuple10[A, B, C, D, E, F, G, H, I, J]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h, FieldI: i, FieldJ: j}
}
// Zip10 create a slice of Tuple10, whose elements are correspond to the given slice elements.
// Play: https://go.dev/play/p/YSR-2cXnrY4
func Zip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, j []J) []Tuple10[A, B, C, D, E, F, G, H, I, J] {
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i), len(j))
tuples := make([]Tuple10[A, B, C, D, E, F, G, H, I, J], size)
for idx := 0; idx < size; idx++ {
v1, _ := getByIndex(a, idx)
v2, _ := getByIndex(b, idx)
v3, _ := getByIndex(c, idx)
v4, _ := getByIndex(d, idx)
v5, _ := getByIndex(e, idx)
v6, _ := getByIndex(f, idx)
v7, _ := getByIndex(g, idx)
v8, _ := getByIndex(h, idx)
v9, _ := getByIndex(i, idx)
v10, _ := getByIndex(j, idx)
tuples[idx] = Tuple10[A, B, C, D, E, F, G, H, I, J]{
FieldA: v1, FieldB: v2, FieldC: v3,
FieldD: v4, FieldE: v5, FieldF: v6,
FieldG: v7, FieldH: v8, FieldI: v9,
FieldJ: v10}
}
return tuples
}
// Unzip10 creates a group of slice from a slice of Tuple10.
// Play: https://go.dev/play/p/-taQB6Wfre_z
func Unzip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](tuples []Tuple10[A, B, C, D, E, F, G, H, I, J]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I, []J) {
size := len(tuples)
r1 := make([]A, size)
r2 := make([]B, size)
r3 := make([]C, size)
r4 := make([]D, size)
r5 := make([]E, size)
r6 := make([]F, size)
r7 := make([]G, size)
r8 := make([]H, size)
r9 := make([]I, size)
r10 := make([]J, size)
for i, t := range tuples {
r1[i] = t.FieldA
r2[i] = t.FieldB
r3[i] = t.FieldC
r4[i] = t.FieldD
r5[i] = t.FieldE
r6[i] = t.FieldF
r7[i] = t.FieldG
r8[i] = t.FieldH
r9[i] = t.FieldI
r10[i] = t.FieldJ
}
return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
}
func getByIndex[T any](slice []T, index int) (T, bool) {
l := len(slice)
if index >= l || -index > l {
var zeroVal T
return zeroVal, false
}
if index >= 0 {
return slice[index], true
}
return slice[l+index], true
}

301
tuple/tuple_example_test.go Normal file
View File

@@ -0,0 +1,301 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package tuple implements tuple data type and some operations on it.
package tuple
import (
"fmt"
)
func ExampleNewTuple2() {
t := NewTuple2(1, 0.1)
fmt.Printf("%v %v", t.FieldA, t.FieldB)
// Output: 1 0.1
}
func ExampleTuple2_Unbox() {
t := NewTuple2(1, 0.1)
v1, v2 := t.Unbox()
fmt.Printf("%v %v", v1, v2)
// Output: 1 0.1
}
func ExampleZip2() {
result := Zip2([]int{1}, []float64{0.1})
fmt.Println(result)
// Output: [{1 0.1}]
}
func ExampleUnzip2() {
v1, v2 := Unzip2([]Tuple2[int, float64]{{FieldA: 1, FieldB: 0.1}})
fmt.Printf("%v %v", v1, v2)
// Output: [1] [0.1]
}
func ExampleNewTuple3() {
t := NewTuple3(1, 0.1, "a")
fmt.Printf("%v %v %v", t.FieldA, t.FieldB, t.FieldC)
// Output: 1 0.1 a
}
func ExampleTuple3_Unbox() {
t := NewTuple3(1, 0.1, "a")
v1, v2, v3 := t.Unbox()
fmt.Printf("%v %v %v", v1, v2, v3)
// Output: 1 0.1 a
}
func ExampleZip3() {
result := Zip3([]int{1}, []float64{0.1}, []string{"a"})
fmt.Println(result)
// Output: [{1 0.1 a}]
}
func ExampleUnzip3() {
v1, v2, v3 := Unzip3([]Tuple3[int, float64, string]{
{FieldA: 1, FieldB: 0.1, FieldC: "a"},
})
fmt.Printf("%v %v %v", v1, v2, v3)
// Output: [1] [0.1] [a]
}
func ExampleNewTuple4() {
t := NewTuple4(1, 0.1, "a", true)
fmt.Printf("%v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD)
// Output: 1 0.1 a true
}
func ExampleTuple4_Unbox() {
t := NewTuple4(1, 0.1, "a", true)
v1, v2, v3, v4 := t.Unbox()
fmt.Printf("%v %v %v %v", v1, v2, v3, v4)
// Output: 1 0.1 a true
}
func ExampleZip4() {
result := Zip4([]int{1}, []float64{0.1}, []string{"a"}, []bool{true})
fmt.Println(result)
// Output: [{1 0.1 a true}]
}
func ExampleUnzip4() {
v1, v2, v3, v4 := Unzip4([]Tuple4[int, float64, string, bool]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true},
})
fmt.Printf("%v %v %v %v", v1, v2, v3, v4)
// Output: [1] [0.1] [a] [true]
}
func ExampleNewTuple5() {
t := NewTuple5(1, 0.1, "a", true, 2)
fmt.Printf("%v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE)
// Output: 1 0.1 a true 2
}
func ExampleTuple5_Unbox() {
t := NewTuple5(1, 0.1, "a", true, 2)
v1, v2, v3, v4, v5 := t.Unbox()
fmt.Printf("%v %v %v %v %v", v1, v2, v3, v4, v5)
// Output: 1 0.1 a true 2
}
func ExampleZip5() {
result := Zip5([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2})
fmt.Println(result)
// Output: [{1 0.1 a true 2}]
}
func ExampleUnzip5() {
v1, v2, v3, v4, v5 := Unzip5([]Tuple5[int, float64, string, bool, int]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2},
})
fmt.Printf("%v %v %v %v %v", v1, v2, v3, v4, v5)
// Output: [1] [0.1] [a] [true] [2]
}
func ExampleNewTuple6() {
t := NewTuple6(1, 0.1, "a", true, 2, 2.2)
fmt.Printf("%v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF)
// Output: 1 0.1 a true 2 2.2
}
func ExampleTuple6_Unbox() {
t := NewTuple6(1, 0.1, "a", true, 2, 2.2)
v1, v2, v3, v4, v5, v6 := t.Unbox()
fmt.Printf("%v %v %v %v %v %v", v1, v2, v3, v4, v5, v6)
// Output: 1 0.1 a true 2 2.2
}
func ExampleZip6() {
result := Zip6([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2}, []float32{2.2})
fmt.Println(result)
// Output: [{1 0.1 a true 2 2.2}]
}
func ExampleUnzip6() {
v1, v2, v3, v4, v5, v6 := Unzip6([]Tuple6[int, float64, string, bool, int, float32]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2},
})
fmt.Printf("%v %v %v %v %v %v", v1, v2, v3, v4, v5, v6)
// Output: [1] [0.1] [a] [true] [2] [2.2]
}
func ExampleNewTuple7() {
t := NewTuple7(1, 0.1, "a", true, 2, 2.2, "b")
fmt.Printf("%v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG)
// Output: 1 0.1 a true 2 2.2 b
}
func ExampleTuple7_Unbox() {
t := NewTuple7(1, 0.1, "a", true, 2, 2.2, "b")
v1, v2, v3, v4, v5, v6, v7 := t.Unbox()
fmt.Printf("%v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7)
// Output: 1 0.1 a true 2 2.2 b
}
func ExampleZip7() {
result := Zip7([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2}, []float32{2.2}, []string{"b"})
fmt.Println(result)
// Output: [{1 0.1 a true 2 2.2 b}]
}
func ExampleUnzip7() {
v1, v2, v3, v4, v5, v6, v7 := Unzip7([]Tuple7[int, float64, string, bool, int, float32, string]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b"},
})
fmt.Printf("%v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7)
// Output: [1] [0.1] [a] [true] [2] [2.2] [b]
}
func ExampleNewTuple8() {
t := NewTuple8(1, 0.1, "a", true, 2, 2.2, "b", "c")
fmt.Printf("%v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH)
// Output: 1 0.1 a true 2 2.2 b c
}
func ExampleTuple8_Unbox() {
t := NewTuple8(1, 0.1, "a", true, 2, 2.2, "b", "c")
v1, v2, v3, v4, v5, v6, v7, v8 := t.Unbox()
fmt.Printf("%v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8)
// Output: 1 0.1 a true 2 2.2 b c
}
func ExampleZip8() {
result := Zip8([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2}, []float32{2.2}, []string{"b"}, []string{"c"})
fmt.Println(result)
// Output: [{1 0.1 a true 2 2.2 b c}]
}
func ExampleUnzip8() {
v1, v2, v3, v4, v5, v6, v7, v8 := Unzip8([]Tuple8[int, float64, string, bool, int, float32, string, string]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c"},
})
fmt.Printf("%v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8)
// Output: [1] [0.1] [a] [true] [2] [2.2] [b] [c]
}
func ExampleNewTuple9() {
t := NewTuple9(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
fmt.Printf("%v %v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI)
// Output: 1 0.1 a true 2 2.2 b c map[a:1]
}
func ExampleTuple9_Unbox() {
t := NewTuple9(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
v1, v2, v3, v4, v5, v6, v7, v8, v9 := t.Unbox()
fmt.Printf("%v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9)
// Output: 1 0.1 a true 2 2.2 b c map[a:1]
}
func ExampleZip9() {
result := Zip9([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2}, []float32{2.2}, []string{"b"}, []string{"c"}, []int64{3})
fmt.Println(result)
// Output: [{1 0.1 a true 2 2.2 b c 3}]
}
func ExampleUnzip9() {
v1, v2, v3, v4, v5, v6, v7, v8, v9 := Unzip9([]Tuple9[int, float64, string, bool, int, float32, string, string, int64]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: 3},
})
fmt.Printf("%v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9)
// Output: [1] [0.1] [a] [true] [2] [2.2] [b] [c] [3]
}
func ExampleNewTuple10() {
type foo struct {
A string
}
t := NewTuple10(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI, t.FieldJ)
// Output: 1 0.1 a true 2 2.2 b c map[a:1] {a}
}
func ExampleTuple10_Unbox() {
type foo struct {
A string
}
t := NewTuple10(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 := t.Unbox()
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
// Output: 1 0.1 a true 2 2.2 b c map[a:1] {a}
}
func ExampleZip10() {
result := Zip10([]int{1}, []float64{0.1}, []string{"a"}, []bool{true}, []int{2}, []float32{2.2}, []string{"b"}, []string{"c"}, []int64{3}, []bool{false})
fmt.Println(result)
// Output: [{1 0.1 a true 2 2.2 b c 3 false}]
}
func ExampleUnzip10() {
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 := Unzip10([]Tuple10[int, float64, string, bool, int, float32, string, string, int64, bool]{
{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: 3, FieldJ: false},
})
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
// Output: [1] [0.1] [a] [true] [2] [2.2] [b] [c] [3] [false]
}

195
tuple/tuple_test.go Normal file
View File

@@ -0,0 +1,195 @@
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package tuple implements tuple data type and some operations on it.
package tuple
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestTuples(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTuples")
type foo struct {
A string
}
t2 := NewTuple2[int, float64](1, 0.1)
t3 := NewTuple3[int, float64, string](1, 0.1, "a")
t4 := NewTuple4[int, float64, string, bool](1, 0.1, "a", true)
t5 := NewTuple5[int, float64, string, bool, int64](1, 0.1, "a", true, 2)
t6 := NewTuple6[int, float64, string, bool, int64, float32](1, 0.1, "a", true, 2, 2.2)
t7 := NewTuple7[int, float64, string, bool, int64, float32, string](1, 0.1, "a", true, 2, 2.2, "b")
t8 := NewTuple8[int, float64, string, bool, int64, float32, string, string](1, 0.1, "a", true, 2, 2.2, "b", "c")
t9 := NewTuple9[int, float64, string, bool, int64, float32, string, string, map[string]int](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
t10 := NewTuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
assert.Equal(t2, Tuple2[int, float64]{FieldA: 1, FieldB: 0.1})
assert.Equal(t3, Tuple3[int, float64, string]{FieldA: 1, FieldB: 0.1, FieldC: "a"})
assert.Equal(t4, Tuple4[int, float64, string, bool]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true})
assert.Equal(t5, Tuple5[int, float64, string, bool, int64]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2})
assert.Equal(t6, Tuple6[int, float64, string, bool, int64, float32]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2})
assert.Equal(t7, Tuple7[int, float64, string, bool, int64, float32, string]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b"})
assert.Equal(t8, Tuple8[int, float64, string, bool, int64, float32, string, string]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c"})
assert.Equal(t9, Tuple9[int, float64, string, bool, int64, float32, string, string, map[string]int]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: map[string]int{"a": 1}})
assert.Equal(t10, Tuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: map[string]int{"a": 1}, FieldJ: foo{A: "a"}})
}
func TestTuple_Unbox(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestTuple_Unbox")
type foo struct {
A string
}
t2 := NewTuple2[int, float64](1, 0.1)
v1, v2 := t2.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
t3 := NewTuple3[int, float64, string](1, 0.1, "a")
v1, v2, v3 := t3.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
t4 := NewTuple4[int, float64, string, bool](1, 0.1, "a", true)
v1, v2, v3, v4 := t4.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
t5 := NewTuple5[int, float64, string, bool, int64](1, 0.1, "a", true, 2)
v1, v2, v3, v4, v5 := t5.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
t6 := NewTuple6[int, float64, string, bool, int64, float32](1, 0.1, "a", true, 2, 2.2)
v1, v2, v3, v4, v5, v6 := t6.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
assert.Equal(float32(2.2), v6)
t7 := NewTuple7[int, float64, string, bool, int64, float32, string](1, 0.1, "a", true, 2, 2.2, "b")
v1, v2, v3, v4, v5, v6, v7 := t7.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
assert.Equal(float32(2.2), v6)
assert.Equal("b", v7)
t8 := NewTuple8[int, float64, string, bool, int64, float32, string, string](1, 0.1, "a", true, 2, 2.2, "b", "c")
v1, v2, v3, v4, v5, v6, v7, v8 := t8.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
assert.Equal(float32(2.2), v6)
assert.Equal("b", v7)
assert.Equal("c", v8)
t9 := NewTuple9[int, float64, string, bool, int64, float32, string, string, map[string]int](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
v1, v2, v3, v4, v5, v6, v7, v8, v9 := t9.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
assert.Equal(float32(2.2), v6)
assert.Equal("b", v7)
assert.Equal("c", v8)
assert.Equal(map[string]int{"a": 1}, v9)
t10 := NewTuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 := t10.Unbox()
assert.Equal(1, v1)
assert.Equal(0.1, v2)
assert.Equal("a", v3)
assert.Equal(true, v4)
assert.Equal(int64(2), v5)
assert.Equal(float32(2.2), v6)
assert.Equal("b", v7)
assert.Equal("c", v8)
assert.Equal(map[string]int{"a": 1}, v9)
assert.Equal(foo{A: "a"}, v10)
}
func TestZip(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestZip")
r2 := Zip2(
[]int{1, 2},
[]string{"a", "b"},
)
assert.Equal(r2, []Tuple2[int, string]{
{FieldA: 1, FieldB: "a"},
{FieldA: 2, FieldB: "b"},
})
r3 := Zip3(
[]int{1, 2, 3},
[]string{"a", "b", "c"},
[]float64{0.1, 0.2, 0.3},
)
assert.Equal(r3, []Tuple3[int, string, float64]{
{FieldA: 1, FieldB: "a", FieldC: 0.1},
{FieldA: 2, FieldB: "b", FieldC: 0.2},
{FieldA: 3, FieldB: "c", FieldC: 0.3},
})
r4 := Zip4(
[]int{1, 2, 3, 4},
[]string{"a", "b", "c", "d"},
[]float64{0.1, 0.2, 0.3, 0.4},
[]bool{true, true, true, true},
)
assert.Equal(r4, []Tuple4[int, string, float64, bool]{
{FieldA: 1, FieldB: "a", FieldC: 0.1, FieldD: true},
{FieldA: 2, FieldB: "b", FieldC: 0.2, FieldD: true},
{FieldA: 3, FieldB: "c", FieldC: 0.3, FieldD: true},
{FieldA: 4, FieldB: "d", FieldC: 0.4, FieldD: true},
})
r5 := Zip5(
[]int{1, 2, 3, 4, 5},
[]string{"a", "b", "c", "d", "e"},
[]float64{0.1, 0.2, 0.3, 0.4, 0.5},
[]bool{true, true, true, true, true},
[]int{6, 7, 8, 9, 10},
)
assert.Equal(r5, []Tuple5[int, string, float64, bool, int]{
{FieldA: 1, FieldB: "a", FieldC: 0.1, FieldD: true, FieldE: 6},
{FieldA: 2, FieldB: "b", FieldC: 0.2, FieldD: true, FieldE: 7},
{FieldA: 3, FieldB: "c", FieldC: 0.3, FieldD: true, FieldE: 8},
{FieldA: 4, FieldB: "d", FieldC: 0.4, FieldD: true, FieldE: 9},
{FieldA: 5, FieldB: "e", FieldC: 0.5, FieldD: true, FieldE: 10},
})
}
func TestUnzip(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUnzip")
r1, r2, r3 := Unzip3([]Tuple3[string, int, float64]{{FieldA: "a", FieldB: 1, FieldC: 0.1}, {FieldA: "b", FieldB: 2, FieldC: 0.2}})
assert.Equal(r1, []string{"a", "b"})
assert.Equal(r2, []int{1, 2})
assert.Equal(r3, []float64{0.1, 0.2})
}

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