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

Compare commits

...

68 Commits

Author SHA1 Message Date
dudaodong
6314889c6a release v2.1.7 2022-10-14 10:08:43 +08:00
dudaodong
294bd5a5ed doc: update document for hashmap 2022-10-11 15:41:09 +08:00
dudaodong
ca44815fd5 Merge branch 'main' into v2 2022-10-11 15:02:28 +08:00
dudaodong
bcd1cabf80 feat: add Keys and Values function for hashmap 2022-10-10 16:34:05 +08:00
CyJaySong
4edefcca67 expand BeginOfWeek、EndOfWeek (#59) 2022-10-10 15:44:22 +08:00
dudaodong
fab24c8d12 feat: add Iterate for hashmap datastructure 2022-10-10 15:25:30 +08:00
dudaodong
604acd9b07 doc:add lancet api doc website 2022-09-29 18:41:22 +08:00
dudaodong
531cb19fd1 release v2.1.6 2022-08-31 17:07:32 +08:00
dudaodong
4f0161ca53 doc: add source code link for http_client 2022-08-31 15:56:41 +08:00
dudaodong
73362b7f69 doc: update readme file 2022-08-31 11:40:24 +08:00
dudaodong
b289f2975b doc: add document for functions in netutil/http_client.go 2022-08-31 11:20:22 +08:00
dudaodong
90ce2705ca test: add unit test for http client 2022-08-30 17:33:58 +08:00
dudaodong
35e1d09ce3 feat: add http client for sending http request 2022-08-30 17:22:17 +08:00
dudaodong
d67d8fad3a doc: fix missing word in file condition.md 2022-08-29 14:02:30 +08:00
dudaodong
c5e6d01a31 update readme file: add new package and function 2022-08-29 11:50:37 +08:00
dudaodong
6d6c3f692f refactor: change TernaryOperator signature 2022-08-29 11:27:51 +08:00
dudaodong
c695837b16 doc: add document for package condition 2022-08-29 11:23:02 +08:00
dudaodong
ef28b52963 fix: fix regex isChineseMobileRegexMatcher not work 2022-08-28 20:58:34 +08:00
dudaodong
18b2b6ff7c feat: add functons: And, Or, Xor, Nor, Xnor, Nand 2022-08-28 20:57:28 +08:00
dudaodong
6a05a123f4 feat: add Bool function to check if a value is truthy or falsy 2022-08-28 20:38:19 +08:00
dudaodong
f7c33f258d Merge branch 'main' into v2 2022-08-27 19:25:24 +08:00
dudaodong
04058dd7da refactor: change common package to condition package 2022-08-27 19:19:34 +08:00
郑一诺她爸
72e1d92fa1 TernaryOperator Reduce if else operations (#56)
* feat:(slice add AppendIfAbsent function)

* feat:(slice add TernaryOperator function)

Co-authored-by: george.zheng <george.zheng@ambergroup.io>
2022-08-27 19:12:03 +08:00
dudaodong
063df0f0d1 doc: add docment for IsZeroValue function 2022-08-27 19:04:57 +08:00
dudaodong
fc10689b25 feat: add IsZeroValue function 2022-08-27 18:57:45 +08:00
dudaodong
9239bcfdc3 doc: fmt code example 2022-08-26 16:34:20 +08:00
dudaodong
c984815dea doc: fmt code example 2022-08-26 16:29:55 +08:00
dudaodong
301cb5db87 doc: add hashmap 2022-08-26 16:26:16 +08:00
dudaodong
cc1bacff74 doc: add document for EncodeByte and DecodeByte 2022-08-26 10:54:51 +08:00
dudaodong
f49f75b371 test: add unit test for EncodeByte and DecodeByte 2022-08-26 10:47:25 +08:00
dudaodong
b30f4a7bab feat: add DecodeByte 2022-08-26 10:35:54 +08:00
dudaodong
982cb8932b feat: add EncodeByte 2022-08-26 10:34:42 +08:00
dudaodong
9107eb4b32 fix: fix resize bug in HashMap 2022-08-25 14:04:26 +08:00
dudaodong
1acf977b24 release v2.1.5 2022-08-25 11:11:36 +08:00
dudaodong
5c878d0873 doc: change ReverseStr to Reverse in all docment 2022-08-24 10:37:56 +08:00
dudaodong
ab0716a472 refactor: change ReverseStr to Reverse in strutil package 2022-08-24 10:35:18 +08:00
dudaodong
3c2e0ca5b3 doc: add document for hashmap 2022-08-24 10:28:57 +08:00
dudaodong
551e66ba29 refactor: update HashMap Put method 2022-08-24 10:20:02 +08:00
dudaodong
4eeeabb227 feat: add Delete method for hashmap 2022-08-23 15:07:54 +08:00
dudaodong
b3437fdddf feat: add Delete method for hashmap 2022-08-23 15:07:13 +08:00
dudaodong
312dcab369 feat: add Delete method for hashmap 2022-08-23 15:05:32 +08:00
dudaodong
0cb89f4f46 test: add unit test for HashMap 2022-08-23 14:15:51 +08:00
dudaodong
a2dec87995 feat: add Put method for hashmap 2022-08-23 14:11:14 +08:00
dudaodong
9094cb29bf feat: add new HashMap data structure 2022-08-22 15:21:30 +08:00
dudaodong
ddb992ad2f refactor: BuildMaxHeap 2022-08-22 11:10:17 +08:00
dudaodong
24f18aaaec refactor: change function sign for QuickSort 2022-08-22 11:02:25 +08:00
dudaodong
36169874e5 refactor: change sort file name 2022-08-22 10:58:47 +08:00
dudaodong
23aeb6ac99 refactor: change sort file name 2022-08-22 10:57:04 +08:00
dudaodong
a1984f0a59 feat: add BuildMaxHeap 2022-08-22 10:51:37 +08:00
IceCafeCup
c95db23d2c feat: Set struct uses empty struct as value (#55) 2022-08-13 12:39:30 +08:00
Abirdcfly
fbf251d805 delete minor unreachable code caused by log.Fatal (#54)
Signed-off-by: Abirdcfly <fp544037857@gmail.com>
2022-08-10 14:19:21 +08:00
dudaodong
337f08a04b fix: issue #53 2022-08-06 17:41:45 +08:00
dudaodong
c6a7371049 change lastest v1 version 2022-08-03 10:02:46 +08:00
dudaodong
b697858038 release v2.1.4 2022-08-03 09:56:02 +08:00
dudaodong
5446f7e33c doc: add document for list methods 2022-07-28 12:56:11 +08:00
dudaodong
553f63e76b refactor: update param name in AppendIfAbsent 2022-07-27 15:45:34 +08:00
dudaodong
fc3e94df58 doc: add document for AppendIfAbsent function 2022-07-27 15:44:54 +08:00
dudaodong
5c66f38a5b test: fix test function name TestAppendIfAbsent 2022-07-27 15:38:51 +08:00
郑一诺她爸
70e213b3f7 feat:(slice add AppendIfAbsent function) (#52)
Co-authored-by: george.zheng <george.zheng@ambergroup.io>
2022-07-25 20:52:33 +08:00
donutloop
c1b7500bcb List: add cap (#51)
Cap return cap of the inner data
2022-07-25 20:50:31 +08:00
donutloop
3d7600a9e4 list: add DeleteIf method (#50)
DeleteIf delete all satisfying f(data[i]), returns count of removed elements
2022-07-23 18:52:29 +08:00
donutloop
0299c454ab list: add sublist method (#49)
SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
2022-07-23 15:00:04 +08:00
dudaodong
741af66404 test: add todo fix for TestSchedule 2022-07-22 10:30:44 +08:00
dudaodong
ef5d0379a1 doc: fix missing word 2022-07-22 10:24:34 +08:00
dudaodong
105ab49763 refactor: change slice Contain logic, convert to map first, then check existence 2022-07-22 10:22:34 +08:00
dudaodong
b5ba9ba573 fix: fix TestMapToSlice function result independent of order of elements 2022-07-22 10:17:23 +08:00
donutloop
ac3baac5c6 list: Add LastIndexOfFunc and IndexOfFunc method (#48)
* LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
* IndexOfFunc returns the first index satisfying f(v)
2022-07-22 10:04:31 +08:00
donutloop
a82b5dd206 list: add LastIndexOf (#46)
Add LastIndexOf method too List and fix doc

LastIndexOf returns the index of the last occurrence of the value in this list.
if not found return -1
2022-07-21 15:19:18 +08:00
47 changed files with 3568 additions and 169 deletions

View File

@@ -1,10 +1,10 @@
<div align=center>
<img src="./logo.png" width="200" height="200"/>
<a href="https://uvdream.github.io/lancet-docs/en/"><img src="./logo.png" width="200" height="200"/></a>
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.7-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)
@@ -35,9 +35,9 @@ 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. now latest v1 is v1.3.0. </b>
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.2. </b>
```go
go get github.com/duke-git/lancet@v1.3.0 // below go1.18, install latest version of v1.x.x
go get github.com/duke-git/lancet@v1.3.2 // below go1.18, install latest version of v1.x.x
```
## Usage
@@ -50,7 +50,7 @@ import "github.com/duke-git/lancet/v2/strutil"
## Example
Here takes the string function ReverseStr (reverse order string) as an example, and the strutil package needs to be imported.
Here takes the string function Reverse (reverse order string) as an example, and the strutil package needs to be imported.
```go
package main
@@ -62,13 +62,13 @@ import (
func main() {
s := "hello"
rs := strutil.ReverseStr(s)
rs := strutil.Reverse(s)
fmt.Println(rs) //olleh
}
```
## API Documentation
## [lancet API doc](https://uvdream.github.io/lancet-docs/) Thanks [@UvDream](https://github.com/UvDream) for contributing.
### 1. Algorithm package implements some basic algorithm. eg. sort, search.
```go
@@ -107,7 +107,22 @@ import "github.com/duke-git/lancet/v2/concurrency"
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency.md#Tee)
### 3. Convertor package contains some functions for data convertion.
### 3. Condition package contains some functions for conditional judgment. eg. And, Or, TernaryOperator...
```go
import "github.com/duke-git/lancet/v2/condition"
```
#### Function list:
- [Bool](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Bool)
- [And](https://github.com/duke-git/lancet/blob/main/docs/condition.md#And)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Or)
- [Xor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Xor)
- [Nor](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nor)
- [Nand](https://github.com/duke-git/lancet/blob/main/docs/condition.md#Nand)
- [TernaryOperator](https://github.com/duke-git/lancet/blob/main/docs/condition.md#TernaryOperator)
### 4. Convertor package contains some functions for data convertion.
```go
import "github.com/duke-git/lancet/v2/convertor"
@@ -127,8 +142,10 @@ import "github.com/duke-git/lancet/v2/convertor"
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#StructToMap)
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#MapToSlice)
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#EncodeByte)
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#DecodeByte)
### 4. Cryptor package is for data encryption and decryption.
### 5. Cryptor package is for data encryption and decryption.
```go
import "github.com/duke-git/lancet/v2/cryptor"
@@ -168,7 +185,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor.md#RsaDecrypt)
### 5. Datetime package supports date and time format and compare.
### 6. Datetime package supports date and time format and compare.
```go
@@ -208,7 +225,7 @@ import "github.com/duke-git/lancet/v2/datetime"
### 6. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
### 7. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
```go
@@ -219,6 +236,7 @@ import queue "github.com/duke-git/lancet/v2/datastructure/queue"
import set "github.com/duke-git/lancet/v2/datastructure/set"
import tree "github.com/duke-git/lancet/v2/datastructure/tree"
import heap "github.com/duke-git/lancet/v2/datastructure/heap"
import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
```
#### Function list:
- [List](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list.md)
@@ -228,9 +246,10 @@ import heap "github.com/duke-git/lancet/v2/datastructure/heap"
- [Set](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set.md)
- [Tree](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree.md)
- [Heap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap.md)
- [HashMap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)
### 7. Fileutil package implements some basic functions for file operations.
### 8. Fileutil package implements some basic functions for file operations.
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -254,7 +273,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)
### 8. Formatter contains some functions for data formatting.
### 9. Formatter contains some functions for data formatting.
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -262,7 +281,7 @@ import "github.com/duke-git/lancet/v2/formatter"
#### Function list:
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Comma)
### 9. Function package can control the flow of function execution and support part of functional programming
### 10. Function package can control the flow of function execution and support part of functional programming
```go
import "github.com/duke-git/lancet/v2/function"
@@ -278,7 +297,7 @@ import "github.com/duke-git/lancet/v2/function"
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function.md#Watcher)
### 10. Maputil package includes some functions to manipulate map.
### 11. Maputil package includes some functions to manipulate map.
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -295,7 +314,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#IsDisjoint)
### 11. Mathutil package implements some functions for math calculation.
### 12. Mathutil package implements some functions for math calculation.
```go
import "github.com/duke-git/lancet/v2/mathutil"
@@ -316,7 +335,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)
### 12. Netutil package contains functions to get net information and send http request.
### 13. Netutil package contains functions to get net information and send http request.
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -324,22 +343,28 @@ import "github.com/duke-git/lancet/v2/netutil"
#### Function list:
- [ConvertMapToQueryString](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ConvertMapToQueryString)
- [EncodeUrl](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#EncodeUrl)
- [EncodeUrl](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#EncodeUrl)
- [GetInternalIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetInternalIp)
- [GetIps](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetIps)
- [GetMacAddrs](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetMacAddrs)
- [GetPublicIpInfo](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetPublicIpInfo)
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#IsInternalIP)
- [HttpRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpRequest)
- [HttpClient](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpClient)
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#SendRequest)
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#DecodeResponse)
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPost)
- [HttpPut<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil.md#ParseHttpResponse)
### 13. Random package implements some basic functions to generate random int and string.
### 14. Random package implements some basic functions to generate random int and string.
```go
import "github.com/duke-git/lancet/v2/random"
@@ -351,7 +376,7 @@ import "github.com/duke-git/lancet/v2/random"
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandString)
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
### 14. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
### 15. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -364,13 +389,14 @@ import "github.com/duke-git/lancet/v2/retry"
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryDuration)
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry.md#RetryTimes)
### 15. Slice contains some functions to manipulate slice.
### 16. Slice contains some functions to manipulate slice.
```go
import "github.com/duke-git/lancet/v2/slice"
```
#### Function list:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Chunk)
@@ -415,7 +441,7 @@ import "github.com/duke-git/lancet/v2/slice"
- [UpdateAt](https://github.com/duke-git/lancet/blob/main/docs/slice.md#UpdateAt)
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Without)
### 16. Strutil package contains some functions to manipulate string.
### 17. Strutil package contains some functions to manipulate string.
```go
import "github.com/duke-git/lancet/v2/strutil"
```
@@ -434,13 +460,13 @@ import "github.com/duke-git/lancet/v2/strutil"
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReverseStr)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Unwrap)
### 17. System package contain some functions about os, runtime, shell command.
### 19. System package contain some functions about os, runtime, shell command.
```go
import "github.com/duke-git/lancet/v2/system"
@@ -456,7 +482,7 @@ import "github.com/duke-git/lancet/v2/system"
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system.md#ExecCommand)
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)
### 18. Validator package contains some functions for data validation.
### 19. Validator package contains some functions for data validation.
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -490,7 +516,8 @@ import "github.com/duke-git/lancet/v2/validator"
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsWeakPassword)
### 19. xerror package implements helpers for errors.
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsZeroValue)
### 20. xerror package implements helpers for errors.
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -1,10 +1,10 @@
<div align=center>
<img src="./logo.png" width="200" height="200"/>
<a href="https://uvdream.github.io/lancet-docs/"><img src="./logo.png" width="200" height="200"/><a/>
<br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.1.3-green.svg)](https://github.com/duke-git/lancet/releases)
[![Release](https://img.shields.io/badge/release-2.1.7-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)
@@ -35,9 +35,9 @@
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
```
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.3.0。</b>
2. <b>使用go1.18以下版本的用户必须安装v1.x.x。目前最新的v1版本是v1.3.2。</b>
```go
go get github.com/duke-git/lancet@v1.3.0 // 使用go1.18以下版本, 必须安装v1.x.x版本
go get github.com/duke-git/lancet@v1.3.2 // 使用go1.18以下版本, 必须安装v1.x.x版本
```
## 用法
@@ -50,7 +50,7 @@ import "github.com/duke-git/lancet/v2/strutil"
## 例子
此处以字符串工具函数ReverseStr逆序字符串为例需要导入strutil包:
此处以字符串工具函数Reverse逆序字符串为例需要导入strutil包:
```go
package main
@@ -62,13 +62,13 @@ import (
func main() {
s := "hello"
rs := strutil.ReverseStr(s)
rs := strutil.Reverse(s)
fmt.Println(rs) //olleh
}
```
## API文档
## [lancet API doc](https://uvdream.github.io/lancet-docs/) 感谢[@UvDream](https://github.com/UvDream)整理
### 1. algorithm算法包实现一些基本算法。eg. sort, search.
```go
@@ -89,7 +89,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
### 2. 并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
### 2. concurrency并发包包含一些支持并发编程的功能。例如goroutine, channel, async等。
```go
import "github.com/duke-git/lancet/v2/concurrency"
@@ -105,8 +105,23 @@ import "github.com/duke-git/lancet/v2/concurrency"
- [RepeatFn](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#RepeatFn)
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
### 3. condition条件包含一些用于条件判断的函数。eg. And, Or, TernaryOperator...
```go
import "github.com/duke-git/lancet/v2/condition"
```
#### Function list:
- [Bool](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Bool)
- [And](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#And)
- [Or](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Or)
- [Xor](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Xor)
- [Nor](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nor)
- [Nand](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#Nand)
- [TernaryOperator](https://github.com/duke-git/lancet/blob/main/docs/condition_zh-CN.md#TernaryOperator)
### 3. convertor转换器包支持一些常见的数据类型转换。
### 4. convertor转换器包支持一些常见的数据类型转换。
```go
import "github.com/duke-git/lancet/v2/convertor"
@@ -126,7 +141,10 @@ import "github.com/duke-git/lancet/v2/convertor"
- [ToString](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToString)
- [StructToMap](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#StructToMap)
- [MapToSlice](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#MapToSlice)
### 4. cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#EncodeByte)
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)
### 5. cryptor加密包支持数据加密和解密获取md5hash值。支持base64, md5, hmac, aes, des, rsa。
```go
import "github.com/duke-git/lancet/v2/cryptor"
@@ -166,7 +184,7 @@ import "github.com/duke-git/lancet/v2/cryptor"
- [RsaEncrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaEncrypt)
- [RsaDecrypt](https://github.com/duke-git/lancet/blob/main/docs/cryptor_zh-CN.md#RsaDecrypt)
### 5. datetime日期时间处理包格式化日期比较日期。
### 6. datetime日期时间处理包格式化日期比较日期。
```go
@@ -205,7 +223,7 @@ import "github.com/duke-git/lancet/v2/datetime"
- [ToIso8601](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)
### 6. datastructure包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
### 7. datastructure包含一些普通的数据结构实现。例如list, linklist, stack, queue, set, tree, graph.
```go
@@ -216,6 +234,7 @@ import queue "github.com/duke-git/lancet/v2/datastructure/queue"
import set "github.com/duke-git/lancet/v2/datastructure/set"
import tree "github.com/duke-git/lancet/v2/datastructure/tree"
import heap "github.com/duke-git/lancet/v2/datastructure/heap"
import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
```
#### Function list:
- [List](https://github.com/duke-git/lancet/blob/main/docs/datastructure/list_zh-CN.md)
@@ -225,9 +244,10 @@ import heap "github.com/duke-git/lancet/v2/datastructure/heap"
- [Set](https://github.com/duke-git/lancet/blob/main/docs/datastructure/set_zh-CN.md)
- [Tree](https://github.com/duke-git/lancet/blob/main/docs/datastructure/tree_zh-CN.md)
- [Heap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap.md)
- [HashMap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)
### 7. fileutil包支持文件基本操作。
### 8. fileutil包支持文件基本操作。
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -251,7 +271,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
- [Zip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)
- [UnZip](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)
### 8. formatter格式化器包含一些数据格式化处理方法。
### 9. formatter格式化器包含一些数据格式化处理方法。
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -260,7 +280,7 @@ import "github.com/duke-git/lancet/v2/formatter"
- [Comma](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Comma)
### 9. function函数包控制函数执行流程包含部分函数式编程。
### 10. function函数包控制函数执行流程包含部分函数式编程。
```go
import "github.com/duke-git/lancet/v2/function"
@@ -276,7 +296,7 @@ import "github.com/duke-git/lancet/v2/function"
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
### 10. maputil包包括一些操作map的函数.
### 11. maputil包包括一些操作map的函数.
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -292,7 +312,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)
### 11. mathutil包实现了一些数学计算的函数。
### 12. mathutil包实现了一些数学计算的函数。
```go
import "github.com/duke-git/lancet/v2/mathutil"
@@ -312,7 +332,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
### 12. netutil网络包支持获取ip地址发送http请求。
### 13. netutil网络包支持获取ip地址发送http请求。
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -328,14 +348,20 @@ import "github.com/duke-git/lancet/v2/netutil"
- [GetRequestPublicIp](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#GetRequestPublicIp)
- [IsPublicIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsPublicIP)
- [IsInternalIP](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#IsInternalIP)
- [HttpGet](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
- [HttpPut](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
- [HttpPatch](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
- [HttpRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpRequest)
- [HttpClient](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpClient)
- [SendRequest](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#SendRequest)
- [DecodeResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#DecodeResponse)
- [StructToUrlValues](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPost)
- [HttpPut<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
### 13. random随机数生成器包可以生成随机[]bytes, int, string。
### 14. random随机数生成器包可以生成随机[]bytes, int, string。
```go
import "github.com/duke-git/lancet/v2/random"
@@ -346,7 +372,7 @@ import "github.com/duke-git/lancet/v2/random"
- [RandInt](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandInt)
- [RandString](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandString)
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
### 14. retry重试执行函数直到函数运行成功或被context cancel。
### 15. retry重试执行函数直到函数运行成功或被context cancel。
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -360,13 +386,14 @@ import "github.com/duke-git/lancet/v2/retry"
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
### 15. slice包包含操作切片的方法集合。
### 16. slice包包含操作切片的方法集合。
```go
import "github.com/duke-git/lancet/v2/slice"
```
#### 函数列表:
- [AppendIfAbsent](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#AppendIfAbsent)
- [Contain](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Contain)
- [ContainSubSlice](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ContainSubSlice)
- [Chunk](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Chunk)
@@ -410,7 +437,7 @@ import "github.com/duke-git/lancet/v2/slice"
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
### 16. strutil包含处理字符串的相关函数。
### 17. strutil包含处理字符串的相关函数。
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -430,14 +457,14 @@ import "github.com/duke-git/lancet/v2/strutil"
- [UpperFirst](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#UpperFirst)
- [PadEnd](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadEnd)
- [PadStart](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#PadStart)
- [ReverseStr](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReverseStr)
- [Reverse](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Reverse)
- [SnakeCase](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SnakeCase)
- [SplitEx](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitEx)
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
### 17. system包含os, runtime, shell command相关函数。
### 18. system包含os, runtime, shell command相关函数。
```go
import "github.com/duke-git/lancet/v2/system"
@@ -454,7 +481,7 @@ import "github.com/duke-git/lancet/v2/system"
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsBits)
### 18. validator验证器包包含常用字符串格式验证函数。
### 19. validator验证器包包含常用字符串格式验证函数。
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -487,9 +514,9 @@ import "github.com/duke-git/lancet/v2/validator"
- [IsStrongPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsStrongPassword)
- [IsUrl](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsUrl)
- [IsWeakPassword](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsWeakPassword)
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
validator.md#IsWeakPassword)
### 19. xerror包实现一些错误处理函数
### 20. xerror包实现一些错误处理函数
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -65,11 +65,15 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
func quickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) {
if lowIndex < highIndex {
p := partition(slice, lowIndex, highIndex, comparator)
QuickSort(slice, lowIndex, p-1, comparator)
QuickSort(slice, p+1, highIndex, comparator)
quickSort(slice, lowIndex, p-1, comparator)
quickSort(slice, p+1, highIndex, comparator)
}
}

View File

@@ -30,14 +30,6 @@ func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
return 0
}
// var peoples = []people{
// {Name: "a", Age: 20},
// {Name: "b", Age: 10},
// {Name: "c", Age: 17},
// {Name: "d", Age: 8},
// {Name: "e", Age: 28},
// }
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
@@ -53,8 +45,6 @@ func (c *intComparator) Compare(v1 any, v2 any) int {
return 0
}
// var intSlice = []int{2, 1, 5, 3, 6, 4}
func TestBubbleSortForStructSlice(t *testing.T) {
asssert := internal.NewAssert(t, "TestBubbleSortForStructSlice")
@@ -151,7 +141,7 @@ func TestQuickSort(t *testing.T) {
{Name: "e", Age: 28},
}
comparator := &peopleAgeComparator{}
QuickSort(peoples, 0, len(peoples)-1, comparator)
QuickSort(peoples, comparator)
expected := "[{d 8} {b 10} {c 17} {a 20} {e 28}]"
actual := fmt.Sprintf("%v", peoples)

77
condition/condition.go Normal file
View File

@@ -0,0 +1,77 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package condition contains some functions for conditional judgment. eg. And, Or, TernaryOperator ...
// The implementation of this package refers to the implementation of carlmjohnson's truthy package, you may find more
// useful information in truthy(https://github.com/carlmjohnson/truthy), thanks carlmjohnson.
package condition
import "reflect"
// Bool returns the truthy value of anything.
// If the value's type has a Bool() bool method, the method is called and returned.
// If the type has an IsZero() bool method, the opposite value is returned.
// Slices and maps are truthy if they have a length greater than zero.
// All other types are truthy if they are not their zero value.
func Bool[T any](value T) bool {
switch m := any(value).(type) {
case interface{ Bool() bool }:
return m.Bool()
case interface{ IsZero() bool }:
return !m.IsZero()
}
return reflectValue(&value)
}
func reflectValue(vp any) bool {
switch rv := reflect.ValueOf(vp).Elem(); rv.Kind() {
case reflect.Map, reflect.Slice:
return rv.Len() != 0
default:
is := rv.IsZero()
return !is
}
}
// And returns true if both a and b are truthy.
func And[T, U any](a T, b U) bool {
return Bool(a) && Bool(b)
}
// Or returns false iff neither a nor b is truthy.
func Or[T, U any](a T, b U) bool {
return Bool(a) || Bool(b)
}
// Xor returns true iff a or b but not both is truthy.
func Xor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA || valB) && valA != valB
}
// Nor returns true iff neither a nor b is truthy.
func Nor[T, U any](a T, b U) bool {
return !(Bool(a) || Bool(b))
}
// Xnor returns true iff both a and b or neither a nor b are truthy.
func Xnor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA && valB) || (!valA && !valB)
}
// Nand returns false iff both a and b are truthy.
func Nand[T, U any](a T, b U) bool {
return !Bool(a) || !Bool(b)
}
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
if Bool(isTrue) {
return ifValue
} else {
return elseValue
}
}

119
condition/condition_test.go Normal file
View File

@@ -0,0 +1,119 @@
package condition
import (
"errors"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
type TestStruct struct{}
func TestBool(t *testing.T) {
assert := internal.NewAssert(t, "TestBool")
// bool
assert.Equal(false, Bool(false))
assert.Equal(true, Bool(true))
// integer
assert.Equal(false, Bool(0))
assert.Equal(true, Bool(1))
// float
assert.Equal(false, Bool(0.0))
assert.Equal(true, Bool(0.1))
// string
assert.Equal(false, Bool(""))
assert.Equal(true, Bool(" "))
assert.Equal(true, Bool("0"))
// slice
var nums [2]int
assert.Equal(false, Bool(nums))
nums = [2]int{0, 1}
assert.Equal(true, Bool(nums))
// map
assert.Equal(false, Bool(map[string]string{}))
assert.Equal(true, Bool(map[string]string{"a": "a"}))
// channel
var ch chan int
assert.Equal(false, Bool(ch))
ch = make(chan int)
assert.Equal(true, Bool(ch))
// interface
var err error
assert.Equal(false, Bool(err))
err = errors.New("error message")
assert.Equal(true, Bool(err))
// struct
assert.Equal(false, Bool(struct{}{}))
assert.Equal(true, Bool(time.Now()))
// struct pointer
ts := TestStruct{}
assert.Equal(false, Bool(ts))
assert.Equal(true, Bool(&ts))
}
func TestAnd(t *testing.T) {
assert := internal.NewAssert(t, "TestAnd")
assert.Equal(false, And(0, 1))
assert.Equal(false, And(0, ""))
assert.Equal(false, And(0, "0"))
assert.Equal(true, And(1, "0"))
}
func TestOr(t *testing.T) {
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Or(0, ""))
assert.Equal(true, Or(0, 1))
assert.Equal(true, Or(0, "0"))
assert.Equal(true, Or(1, "0"))
}
func TestXor(t *testing.T) {
assert := internal.NewAssert(t, "TestOr")
assert.Equal(false, Xor(0, 0))
assert.Equal(true, Xor(0, 1))
assert.Equal(true, Xor(1, 0))
assert.Equal(false, Xor(1, 1))
}
func TestNor(t *testing.T) {
assert := internal.NewAssert(t, "TestNor")
assert.Equal(true, Nor(0, 0))
assert.Equal(false, Nor(0, 1))
assert.Equal(false, Nor(1, 0))
assert.Equal(false, Nor(1, 1))
}
func TestXnor(t *testing.T) {
assert := internal.NewAssert(t, "TestXnor")
assert.Equal(true, Xnor(0, 0))
assert.Equal(false, Xnor(0, 1))
assert.Equal(false, Xnor(1, 0))
assert.Equal(true, Xnor(1, 1))
}
func TestNand(t *testing.T) {
assert := internal.NewAssert(t, "TestNand")
assert.Equal(true, Nand(0, 0))
assert.Equal(true, Nand(0, 1))
assert.Equal(true, Nand(1, 0))
assert.Equal(false, Nand(1, 1))
}
func TestTernaryOperator(t *testing.T) {
assert := internal.NewAssert(t, "TernaryOperator")
trueValue := "1"
falseValue := "0"
assert.Equal(trueValue, TernaryOperator(true, trueValue, falseValue))
}

View File

@@ -7,6 +7,7 @@ package convertor
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"fmt"
"math"
@@ -270,3 +271,21 @@ func ColorRGBToHex(red, green, blue int) string {
return "#" + r + g + b
}
// EncodeByte encode data to byte
func EncodeByte(data any) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
err := encoder.Encode(data)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// DecodeByte decode byte data to target object
func DecodeByte(data []byte, target any) error {
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
return decoder.Decode(target)
}

View File

@@ -6,6 +6,7 @@ import (
"testing"
"github.com/duke-git/lancet/v2/internal"
"github.com/duke-git/lancet/v2/slice"
)
func TestToChar(t *testing.T) {
@@ -204,7 +205,10 @@ func TestMapToSlice(t *testing.T) {
return key + ":" + strconv.Itoa(value)
})
assert.Equal([]string{"a:1", "b:2", "c:3"}, result)
assert.Equal(3, len(result))
assert.Equal(true, slice.Contain(result, "a:1"))
assert.Equal(true, slice.Contain(result, "b:2"))
assert.Equal(true, slice.Contain(result, "c:3"))
}
func TestColorHexToRGB(t *testing.T) {
@@ -234,3 +238,21 @@ func TestToPointer(t *testing.T) {
assert.Equal(*result, 123)
}
func TestEncodeByte(t *testing.T) {
assert := internal.NewAssert(t, "TestEncodeByte")
byteData, _ := EncodeByte("abc")
expected := []byte{6, 12, 0, 3, 97, 98, 99}
assert.Equal(expected, byteData)
}
func TestDecodeByte(t *testing.T) {
assert := internal.NewAssert(t, "TestDecodeByte")
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
DecodeByte(byteData, &obj)
assert.Equal("abc", obj)
}

View File

@@ -0,0 +1,175 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
package datastructure
import (
"fmt"
"hash/fnv"
)
var defaultMapCapacity uint64 = 1 << 10
type mapNode struct {
key any
value any
next *mapNode
}
//HashMap implements a hash map
type HashMap struct {
capacity uint64
size uint64
table []*mapNode
}
// NewHashMap return a HashMap instance
func NewHashMap() *HashMap {
return &HashMap{
capacity: defaultMapCapacity,
table: make([]*mapNode, defaultMapCapacity),
}
}
// NewHashMapWithCapacity return a HashMap instance with given size and capacity
func NewHashMapWithCapacity(size, capacity uint64) *HashMap {
return &HashMap{
size: size,
capacity: capacity,
table: make([]*mapNode, capacity),
}
}
// Get return the value of given key in hashmap
func (hm *HashMap) Get(key any) any {
hashValue := hm.hash(key)
node := hm.table[hashValue]
if node != nil {
return node.value
}
return nil
}
// Put new key value in hashmap
func (hm *HashMap) Put(key any, value any) {
hm.putValue(hm.hash(key), key, value)
}
func (hm *HashMap) putValue(hash uint64, key, value any) {
if hm.capacity == 0 {
hm.capacity = defaultMapCapacity
hm.table = make([]*mapNode, defaultMapCapacity)
}
node := hm.table[hash]
if node == nil {
hm.table[hash] = newMapNode(key, value)
} else if node.key == key {
hm.table[hash] = newMapNodeWithNext(key, value, node)
} else {
hm.resize()
hm.putValue(hash, value, value)
}
hm.size++
}
// Delete item by given key in hashmap
func (hm *HashMap) Delete(key any) {
hash := hm.hash(key)
node := hm.table[hash]
if node == nil {
return
}
hm.table = append(hm.table[:hash], hm.table[hash+1:]...)
hm.size--
}
// 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
}
// Iterate executes iteratee funcation for every key and value pair of hashmap (random order)
func (hm *HashMap) Iterate(iteratee func(key, value any)) {
if hm.size > 0 {
for i := 0; i < len(hm.table); i++ {
item := hm.table[i]
if item != nil {
iteratee(item.key, item.value)
}
}
}
}
// Keys returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Keys() []any {
keys := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
keys[index] = key
index++
})
}
return keys
}
// Values returns a slice of the hashmap's keys (random order)
func (hm *HashMap) Values() []any {
values := make([]any, int(hm.size))
index := 0
if hm.size > 0 {
hm.Iterate(func(key, value any) {
values[index] = value
index++
})
}
return values
}
func (hm *HashMap) resize() {
hm.capacity <<= 1
tempTable := hm.table
hm.table = make([]*mapNode, hm.capacity)
for i := 0; i < len(tempTable); i++ {
node := tempTable[i]
if node == nil {
continue
}
hm.table[hm.hash(node.key)] = node
}
}
func (hm *HashMap) hash(key any) uint64 {
h := fnv.New64a()
_, _ = h.Write([]byte(fmt.Sprintf("%v", key)))
hashValue := h.Sum64()
return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16))
}
func newMapNode(key, value any) *mapNode {
return &mapNode{
key: key,
value: value,
}
}
func newMapNodeWithNext(key, value any, next *mapNode) *mapNode {
return &mapNode{
key: key,
value: value,
next: next,
}
}

View File

@@ -0,0 +1,71 @@
package datastructure
import (
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHashMap_PutAndGet(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_PutAndGet")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
assert.IsNil(hm.Get("abcd"))
hm.Put("abc", 4)
assert.Equal(4, hm.Get("abc"))
}
func TestHashMap_Resize(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Resize")
hm := NewHashMapWithCapacity(3, 3)
for i := 0; i < 20; i++ {
hm.Put(i, 10)
}
assert.Equal(10, hm.Get(5))
}
func TestHashMap_Delete(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Delete")
hm := NewHashMap()
hm.Put("abc", 3)
assert.Equal(3, hm.Get("abc"))
hm.Delete("abc")
assert.IsNil(hm.Get("abc"))
}
func TestHashMap_Contains(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_Contains")
hm := NewHashMap()
assert.Equal(false, hm.Contains("abc"))
hm.Put("abc", 3)
assert.Equal(true, hm.Contains("abc"))
}
func TestHashMap_KeysValues(t *testing.T) {
assert := internal.NewAssert(t, "TestHashMap_KeysValues")
hm := NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
values := hm.Values()
t.Log(keys, values)
assert.Equal(3, len(values))
assert.Equal(3, len(keys))
}

View File

@@ -25,6 +25,20 @@ func NewMaxHeap[T any](comparator lancetconstraints.Comparator) *MaxHeap[T] {
}
}
// BuildMaxHeap builds a MaxHeap instance with data and given comparator.
func BuildMaxHeap[T any](data []T, comparator lancetconstraints.Comparator) *MaxHeap[T] {
heap := &MaxHeap[T]{
data: make([]T, 0, len(data)),
comparator: comparator,
}
for _, v := range data {
heap.Push(v)
}
return heap
}
// Push value into the heap
func (h *MaxHeap[T]) Push(value T) {
h.data = append(h.data, value)

View File

@@ -20,6 +20,20 @@ func (c *intComparator) Compare(v1, v2 any) int {
return 0
}
func TestMaxHeap_BuildMaxHeap(t *testing.T) {
assert := internal.NewAssert(t, "TestMaxHeap_BuildMaxHeap")
values := []int{6, 5, 2, 4, 7, 10, 12, 1, 3, 8, 9, 11}
heap := BuildMaxHeap(values, &intComparator{})
expected := []int{12, 9, 11, 4, 8, 10, 7, 1, 3, 5, 6, 2}
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
heap.PrintStructure()
}
func TestMaxHeap_Push(t *testing.T) {
assert := internal.NewAssert(t, "TestMaxHeap_Push")

View File

@@ -31,7 +31,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
return &l.data[index], true
}
// IndexOf reture the index of value. if not found return -1
// IndexOf returns the index of value. if not found return -1
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
@@ -44,6 +44,48 @@ func (l *List[T]) IndexOf(value T) int {
return index
}
// LastIndexOf returns the index of the last occurrence of the value in this list.
// if not found return -1
func (l *List[T]) LastIndexOf(value T) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if reflect.DeepEqual(data[i], value) {
index = i
break
}
}
return index
}
// IndexOfFunc returns the first index satisfying f(v)
// if not found return -1
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i, v := range data {
if f(v) {
index = i
break
}
}
return index
}
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
// if not found return -1
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
for i := len(data) - 1; i >= 0; i-- {
if f(data[i]) {
index = i
break
}
}
return index
}
// Contain checks if the value in the list or not
func (l *List[T]) Contain(value T) bool {
data := l.data
@@ -121,6 +163,31 @@ func (l *List[T]) DeleteAt(index int) {
l.data = data
}
// DeleteIf delete all satisfying f(data[i]), returns count of removed elements
func (l *List[T]) DeleteIf(f func(T) bool) int {
data := l.data
size := len(data)
var c int
for index := 0; index < len(data); index++ {
if !f(data[index]) {
continue
}
if index == size-1 {
data = append(data[:index])
} else {
data = append(data[:index], data[index+1:]...)
index--
}
c++
}
if c > 0 {
l.data = data
}
return c
}
// UpdateAt update value of list at index, index shoud between 0 and list size -1
func (l *List[T]) UpdateAt(index int, value T) {
data := l.data
@@ -181,6 +248,11 @@ func (l *List[T]) Size() int {
return len(l.data)
}
// Cap return cap of the inner data
func (l *List[T]) Cap() int {
return cap(l.data)
}
// Swap the value of index i and j in list
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
@@ -243,3 +315,11 @@ func (l *List[T]) Intersection(other *List[T]) *List[T] {
return result
}
// SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T] {
data := l.data[fromIndex:toIndex]
subList := make([]T, len(data))
copy(subList, data)
return NewList(subList)
}

View File

@@ -36,6 +36,51 @@ func TestIndexOf(t *testing.T) {
assert.Equal(-1, i)
}
func TestIndexOfFunc(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3})
i := list.IndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
i = list.IndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(-1, i)
}
func TestLastIndexOf(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOf(3)
assert.Equal(5, i)
i = list.LastIndexOf(10)
assert.Equal(-1, i)
i = list.LastIndexOf(4)
assert.Equal(6, i)
i = list.LastIndexOf(1)
assert.Equal(0, i)
}
func TestLastIndexOfFunc(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOf")
list := NewList([]int{1, 2, 3, 3, 3, 3, 4, 5, 6, 9})
i := list.LastIndexOfFunc(func(a int) bool { return a == 3 })
assert.Equal(5, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 10 })
assert.Equal(-1, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 4 })
assert.Equal(6, i)
i = list.LastIndexOfFunc(func(a int) bool { return a == 1 })
assert.Equal(0, i)
}
func TestContain(t *testing.T) {
assert := internal.NewAssert(t, "TestContain")
@@ -216,6 +261,18 @@ func TestSize(t *testing.T) {
assert.Equal(0, empty.Size())
}
func TestCap(t *testing.T) {
assert := internal.NewAssert(t, "TestCap")
data := make([]int, 0, 100)
list := NewList(data)
assert.Equal(100, list.Cap())
data = make([]int, 0)
list = NewList(data)
assert.Equal(0, list.Cap())
}
func TestSwap(t *testing.T) {
assert := internal.NewAssert(t, "TestSwap")
@@ -270,3 +327,33 @@ func TestIntersection(t *testing.T) {
list3 := list1.Intersection(list2)
assert.Equal(true, expected.Equal(list3))
}
func TestSubSlice(t *testing.T) {
assert := internal.NewAssert(t, "TestSubSlice")
list := NewList([]int{1, 2, 3, 4, 5, 8})
subList := list.SubList(2, 5)
assert.Equal([]int{3, 4, 5}, subList.Data())
}
func BenchmarkSubSlice(b *testing.B) {
list := NewList([]int{1, 2, 3, 4, 5, 8})
for n := 0; n < b.N; n++ {
list.SubList(2, 5)
}
}
func TestDeleteIf(t *testing.T) {
assert := internal.NewAssert(t, "TestDeleteIf")
list := NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
count := list.DeleteIf(func(a int) bool { return a == 1 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(12, count)
count = list.DeleteIf(func(a int) bool { return a == 5 })
assert.Equal([]int{2, 3, 4}, list.Data())
assert.Equal(0, count)
}

View File

@@ -1,7 +1,7 @@
package datastructure
// Set is a data container, like slice, but element of set is not duplicate
type Set[T comparable] map[T]bool
type Set[T comparable] map[T]struct{}
// NewSet return a instance of set
func NewSet[T comparable](values ...T) Set[T] {
@@ -13,7 +13,7 @@ func NewSet[T comparable](values ...T) Set[T] {
// Add value to set
func (s Set[T]) Add(values ...T) {
for _, v := range values {
s[v] = true
s[v] = struct{}{}
}
}

View File

@@ -4,24 +4,24 @@
// Package datetime implements some functions to format date and time.
// Note:
// 1. `format` param in FormatTimeToStr function should be as flow:
//"yyyy-mm-dd hh:mm:ss"
//"yyyy-mm-dd hh:mm"
//"yyyy-mm-dd hh"
//"yyyy-mm-dd"
//"yyyy-mm"
//"mm-dd"
//"dd-mm-yy hh:mm:ss"
//"yyyy/mm/dd hh:mm:ss"
//"yyyy/mm/dd hh:mm"
//"yyyy/mm/dd hh"
//"yyyy/mm/dd"
//"yyyy/mm"
//"mm/dd"
//"dd/mm/yy hh:mm:ss"
//"yyyy"
//"mm"
//"hh:mm:ss"
//"mm:ss"
// "yyyy-mm-dd hh:mm:ss"
// "yyyy-mm-dd hh:mm"
// "yyyy-mm-dd hh"
// "yyyy-mm-dd"
// "yyyy-mm"
// "mm-dd"
// "dd-mm-yy hh:mm:ss"
// "yyyy/mm/dd hh:mm:ss"
// "yyyy/mm/dd hh:mm"
// "yyyy/mm/dd hh"
// "yyyy/mm/dd"
// "yyyy/mm"
// "mm/dd"
// "dd/mm/yy hh:mm:ss"
// "yyyy"
// "mm"
// "hh:mm:ss"
// "mm:ss"
package datetime
import (
@@ -147,16 +147,32 @@ func EndOfDay(t time.Time) time.Time {
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}
// BeginOfWeek return beginning week, week begin from Sunday
func BeginOfWeek(t time.Time) time.Time {
y, m, d := t.AddDate(0, 0, 0-int(BeginOfDay(t).Weekday())).Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
// BeginOfWeek return beginning week, default week begin from Sunday
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
var beginFromWeekday = time.Sunday
if len(beginFrom) > 0 {
beginFromWeekday = beginFrom[0]
}
y, m, d := t.AddDate(0, 0, int(beginFromWeekday-t.Weekday())).Date()
beginOfWeek := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
if beginOfWeek.After(t) {
return beginOfWeek.AddDate(0, 0, -7)
}
return beginOfWeek
}
// EndOfWeek return end week time, week end with Saturday
func EndOfWeek(t time.Time) time.Time {
y, m, d := BeginOfWeek(t).AddDate(0, 0, 7).Add(-time.Nanosecond).Date()
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
// EndOfWeek return end week time, default week end with Saturday
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
var endWithWeekday = time.Saturday
if len(endWith) > 0 {
endWithWeekday = endWith[0]
}
y, m, d := t.AddDate(0, 0, int(endWithWeekday-t.Weekday())).Date()
var endWithWeek = time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
if endWithWeek.Before(t) {
endWithWeek = endWithWeek.AddDate(0, 0, 7)
}
return endWithWeek
}
// BeginOfMonth return beginning of month

View File

@@ -5,7 +5,7 @@ Package algorithm implements some basic algorithm. eg. sort, search.
## Source
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
@@ -248,7 +248,7 @@ func main() {
<b>Signature:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator)
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
```
<b>Example:</b>
@@ -278,7 +278,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}

View File

@@ -5,7 +5,7 @@ algorithm算法包实现一些基本算法sortsearchlrucache。
## 源码
- [https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go](https://github.com/duke-git/lancet/blob/main/algorithm/sorter.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
@@ -249,7 +249,7 @@ func main() {
<b>函数签名:</b>
```go
func QuickSort[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) []T
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
```
<b>Example:</b>
@@ -279,7 +279,7 @@ func main() {
intSlice := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
algorithm.QuickSort(intSlice, 0, len(intSlice)-1, comparator)
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
}

264
docs/condition.md Normal file
View File

@@ -0,0 +1,264 @@
# Condition
Package condition contains some functions for conditional judgment. eg. And, Or, TernaryOperator... The implementation of this package refers to the implementation of carlmjohnson's truthy package, you may find more useful information in [truthy](https://github.com/carlmjohnson/truthy), thanks carlmjohnson.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/condition/condition.go](https://github.com/duke-git/lancet/blob/main/condition/condition.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Bool">Bool</span>
<p>Returns the truthy value of anything.<br/>
If the value's type has a Bool() bool method, the method is called and returned.<br/>
If the type has an IsZero() bool method, the opposite value is returned.<br/>
Slices and maps are truthy if they have a length greater than zero.<br/>
All other types are truthy if they are not their zero value.</p>
<b>Signature:</b>
```go
func Bool[T any](value T) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
fmt.Println(condition.Bool(false)) // false
fmt.Println(condition.Bool(true)) // true
// integer
fmt.Println(condition.Bool(0)) // false
fmt.Println(condition.Bool(1)) // true
// float
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string
fmt.Println(condition.Bool("")) // false
fmt.Println(condition.Bool(" ")) // true
fmt.Println(condition.Bool("0")) // true
// slice
var nums [2]int
fmt.Println(condition.Bool(nums)) // false
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map
fmt.Println(condition.Bool(map[string]string{})) // false
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
// struct
fmt.Println(condition.Bool(struct{}{})) // false
fmt.Println(condition.Bool(time.Now())) // true
}
```
### <span id="And">And</span>
<p>Returns true if both a and b are truthy.</p>
<b>Signature:</b>
```go
func And[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.And(0, 1)) // false
fmt.Println(condition.And(0, "")) // false
fmt.Println(condition.And(0, "0")) // false
fmt.Println(condition.And(1, "0")) // true
}
```
### <span id="Or">Or</span>
<p>Returns false iff neither a nor b is truthy.</p>
<b>Signature:</b>
```go
func Or[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Or(0, "")) // false
fmt.Println(condition.Or(0, 1)) // true
fmt.Println(condition.Or(0, "0")) // true
fmt.Println(condition.Or(1, "0")) // true
}
```
### <span id="Xor">Xor</span>
<p>Returns true iff a or b but not both is truthy.</p>
<b>Signature:</b>
```go
func Xor[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xor(0, 0)) // false
fmt.Println(condition.Xor(0, 1)) // true
fmt.Println(condition.Xor(1, 0)) // true
fmt.Println(condition.Xor(1, 1)) // false
}
```
### <span id="Nor">Nor</span>
<p>Returns true iff neither a nor b is truthy.</p>
<b>Signature:</b>
```go
func Nor[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>Returns false iff both a and b are truthy</p>
<b>Signature:</b>
```go
func Nand[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nand(0, 0)) // true
fmt.Println(condition.Nand(0, 1)) // true
fmt.Println(condition.Nand(1, 0)) // true
fmt.Println(condition.Nand(1, 1)) // false
}
```
### <span id="TernaryOperator">TernaryOperator</span>
<p>Checks the value of param `isTrue`, if true return ifValue else return elseValue</p>
<b>Signature:</b>
```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
trueValue := "1"
falseValue := "0"
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
}
```

263
docs/condition_zh-CN.md Normal file
View File

@@ -0,0 +1,263 @@
# Condition
condition包含一些用于条件判断的函数。这个包的实现参考了carlmjohnson的truthy包的实现更多有用的信息可以在[truthy](https://github.com/carlmjohnson/truthy)中找到感谢carlmjohnson。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/condition/condition.go](https://github.com/duke-git/lancet/blob/main/condition/condition.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/condition"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Bool](#Bool)
- [And](#And)
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
<div STYLE="page-break-after: always;"></div>
## 目录
### <span id="Bool">Bool</span>
<p>返回传入参数的bool值.<br/>
如果出入类型参数含有Bool方法, 会调用该方法并返回<br/>
如果传入类型参数有IsZero方法, 返回IsZero方法返回值的取反<br/>
slices和map的length大于0时返回true否则返回false<br/>
其他类型会判断是否是零值</p>
<b>函数签名:</b>
```go
func Bool[T any](value T) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
// bool
fmt.Println(condition.Bool(false)) // false
fmt.Println(condition.Bool(true)) // true
// integer
fmt.Println(condition.Bool(0)) // false
fmt.Println(condition.Bool(1)) // true
// float
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string
fmt.Println(condition.Bool("")) // false
fmt.Println(condition.Bool(" ")) // true
fmt.Println(condition.Bool("0")) // true
// slice
var nums [2]int
fmt.Println(condition.Bool(nums)) // false
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map
fmt.Println(condition.Bool(map[string]string{})) // false
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
// struct
fmt.Println(condition.Bool(struct{}{})) // false
fmt.Println(condition.Bool(time.Now())) // true
}
```
### <span id="And">And</span>
<p>逻辑且操作当切仅当a和b都为true时返回true</p>
<b>函数签名:</b>
```go
func And[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.And(0, 1)) // false
fmt.Println(condition.And(0, "")) // false
fmt.Println(condition.And(0, "0")) // false
fmt.Println(condition.And(1, "0")) // true
}
```
### <span id="Or">Or</span>
<p>逻辑或操作当切仅当a和b都为false时返回false</p>
<b>函数签名:</b>
```go
func Or[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Or(0, "")) // false
fmt.Println(condition.Or(0, 1)) // true
fmt.Println(condition.Or(0, "0")) // true
fmt.Println(condition.Or(1, "0")) // true
}
```
### <span id="Xor">Xor</span>
<p>逻辑异或操作a和b相同返回falsea和b不相同返回true</p>
<b>函数签名:</b>
```go
func Xor[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xor(0, 0)) // false
fmt.Println(condition.Xor(0, 1)) // true
fmt.Println(condition.Xor(1, 0)) // true
fmt.Println(condition.Xor(1, 1)) // false
}
```
### <span id="Nor">Nor</span>
<p>异或的取反操作</p>
<b>函数签名:</b>
```go
func Nor[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>如果a和b都为真返回false否则返回true</p>
<b>函数签名:</b>
```go
func Nand[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Nand(0, 0)) // true
fmt.Println(condition.Nand(0, 1)) // true
fmt.Println(condition.Nand(1, 0)) // true
fmt.Println(condition.Nand(1, 1)) // false
}
```
### <span id="TernaryOperator">TernaryOperator</span>
<p>三元运算符</p>
<b>函数签名:</b>
```go
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
trueValue := "1"
falseValue := "0"
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
}
```

View File

@@ -34,6 +34,8 @@ import (
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
<div STYLE="page-break-after: always;"></div>
@@ -457,4 +459,59 @@ func main() {
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>Encode data to byte slice.</p>
<b>Signature:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>Decode byte data to target object. target should be a pointer instance.</p>
<b>Signature:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```

View File

@@ -36,6 +36,8 @@ import (
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
- [EncodeByte](#EncodeByte)
- [DecodeByte](#DecodeByte)
<div STYLE="page-break-after: always;"></div>
@@ -489,3 +491,59 @@ func main() {
fmt.Println(result) //[]string{"a:1", "b:2", "c:3"}
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片</p>
<b>函数签名:</b>
```go
func EncodeByte(data any) ([]byte, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
}
```
### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
<b>函数签名:</b>
```go
func DecodeByte(data []byte, target any) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc"
}
```

View File

@@ -0,0 +1,314 @@
# HashMap
HashMap is a key value map data structure.
<div STYLE="page-break-after: always;"></div>
## Source
- [https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go](https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go)
<div STYLE="page-break-after: always;"></div>
## Usage
```go
import (
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [NewHashMap](#NewHashMap)
- [NewHashMapWithCapacity](#NewHashMapWithCapacity)
- [Get](#Get)
- [Put](#Put)
- [Delete](#Delete)
- [Contains](#Contains)
- [Iterate](#Iterate)
- [Keys](#Keys)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="NewHashMap">NewHashMap</span>
<p>Make a HashMap instance with default capacity is 1 << 10.</p>
<b>Signature:</b>
```go
func NewHashMap() *HashMap
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
fmt.Println(hm)
}
```
### <span id="NewHashMap">NewHashMap</span>
<p>Make a HashMap instance with given size and capacity.</p>
<b>Signature:</b>
```go
func NewHashMapWithCapacity(size, capacity uint64) *HashMap
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMapWithCapacity(uint64(100), uint64(1000))
fmt.Println(hm)
}
```
### <span id="Get">Get</span>
<p>Get the value of given key in hashmap</p>
<b>Signature:</b>
```go
func (hm *HashMap) Get(key any) any
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
val := hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Put">Put</span>
<p>Put new key value in hashmap, then return value</p>
<b>Signature:</b>
```go
func (hm *HashMap) Put(key any, value any) any
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
}
```
### <span id="Delete">Delete</span>
<p>Delete key-value item by given key in hashmap.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Delete(key any)
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
hm.Delete("a")
val = hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Contains">Contains</span>
<p>Checks if given key is in hashmap or not.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Contains(key any) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
fmt.Println(hm.Contains("a")) //true
fmt.Println(hm.Contains("b")) //false
}
```
### <span id="Iterate">Iterate</span>
<p>Executes iteratee funcation for every key and value pair of hashmap.</p>
<b>Signature:</b>
```go
func (hm *HashMap) Iterate(iteratee func(key, value any))
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
hm.Iterate(func(key, value any) {
fmt.Println(key)
fmt.Println(value)
})
}
```
### <span id="Keys">Keys</span>
<p>Return a slice of the hashmap's keys (random order).</p>
<b>Signature:</b>
```go
func (hm *HashMap) Keys() []any
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
fmt.Println(keys) //[]interface{"a", "b", "c"}
}
```
### <span id="Values">Values</span>
<p>Return a slice of the hashmap's values (random order).</p>
<b>Signature:</b>
```go
func (hm *HashMap) Values() []any
```
<b>Example:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
values := hm.Values()
fmt.Println(values) //[]interface{2, 1, 3}
}
```

View File

@@ -0,0 +1,308 @@
# HashMap
HashMap 数据结构实现
<div STYLE="page-break-after: always;"></div>
## 源码
- [https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go](https://github.com/duke-git/lancet/blob/main/datastructure/hashmap/hashmap.go)
<div STYLE="page-break-after: always;"></div>
## 用法
```go
import (
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [NewHashMap](#NewHashMap)
- [NewHashMapWithCapacity](#NewHashMapWithCapacity)
- [Get](#Get)
- [Put](#Put)
- [Delete](#Delete)
- [Contains](#Contains)
- [Iterate](#Iterate)
- [Keys](#Keys)
- [Values](#Values)
<div STYLE="page-break-after: always;"></div>
## API 文档
### <span id="NewHashMap">NewHashMap</span>
<p>新建默认容量1 << 10的HashMap指针实例</p>
<b>函数签名:</b>
```go
func NewHashMap() *HashMap
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
fmt.Println(hm)
}
```
### <span id="NewHashMapWithCapacity">NewHashMapWithCapacity</span>
<p>新建指定容量和长度的HashMap指针实例.</p>
<b>函数签名:</b>
```go
func NewHashMapWithCapacity(size, capacity uint64) *HashMap
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMapWithCapacity(uint64(100), uint64(1000))
fmt.Println(hm)
}
```
### <span id="Get">Get</span>
<p>在hashmap中根据key获取值</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Get(key any) any
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
val := hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Put">Put</span>
<p>将key-value放入hashmap中</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Put(key any, value any) any
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
}
```
### <span id="Delete">Delete</span>
<p>将指定的key从hashmap中删除</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Delete(key any)
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
val := hm.Get("a")
fmt.Println(val) //1
hm.Delete("a")
val = hm.Get("a")
fmt.Println(val) //nil
}
```
### <span id="Contains">Contains</span>
<p>判断hashmap中是否包含指定的key</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Contains(key any) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
fmt.Println(hm.Contains("a")) //true
fmt.Println(hm.Contains("b")) //false
}
```
### <span id="Iterate">Iterate</span>
<p>迭代hashmap对每个key和value执行iteratee函数</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Iterate(iteratee func(key, value any))
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
hm.Iterate(func(key, value any) {
fmt.Println(key)
fmt.Println(value)
})
}
```
### <span id="Keys">Keys</span>
<p>返回hashmap所有key的切片 (随机顺序)</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Keys() []any
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
keys := hm.Keys()
fmt.Println(keys) //[]interface{"a", "b", "c"}
}
```
### <span id="Values">Values</span>
<p>返回hashmap所有值的切片 (随机顺序).</p>
<b>函数签名:</b>
```go
func (hm *HashMap) Values() []any
```
<b>例子:</b>
```go
package main
import (
"fmt"
hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
)
func main() {
hm := heap.NewHashMap()
hm.Put("a", 1)
hm.Put("b", 2)
hm.Put("c", 3)
values := hm.Values()
fmt.Println(values) //[]interface{2, 1, 3}
}
```

View File

@@ -26,6 +26,9 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
@@ -38,11 +41,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -167,7 +173,7 @@ func main() {
### <span id="IndexOf">IndexOf</span>
<p>Reture the index of value in the list. if not found return -1</p>
<p>Returns the index of value in the list. if not found return -1</p>
<b>Signature:</b>
@@ -192,6 +198,84 @@ func main() {
}
```
### <span id="LastIndexOf">LastIndexOf</span>
<p> Returns the index of the last occurrence of the value in this list if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOf(1)) // 3
fmt.Println(li.LastIndexOf(0)) //-1
}
```
### <span id="IndexOfFunc">IndexOfFunc</span>
<p> IndexOfFunc returns the first index satisfying f(v). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3})
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 1 })) //0
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
<p>LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i]). if not found return -1</p>
<b>Signature:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="Push">Push</span>
@@ -568,6 +652,36 @@ func main() {
### <span id="Cap">Cap</span>
<p>Cap return cap of the inner data</p>
<b>Signature:</b>
```go
func (l *List[T]) Cap() int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
data := make([]int, 0, 100)
li := list.NewList(data)
fmt.Println(li.Cap()) // 100
}
```
### <span id="Swap">Swap</span>
<p>Swap the value at two index in list</p>
@@ -710,4 +824,61 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>
<b>Signature:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 2, 3, 4, 5, 6})
fmt.Println(l.SubList(2, 5)) // []int{3, 4, 5}
}
```
### <span id="DeleteIf">DeleteIf</span>
<p>DeleteIf delete all satisfying f(data[i]), returns count of removed elements</p>
<b>Signature:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>Example:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
fmt.Println(l.DeleteIf(func(a int) bool { return a == 1 })) // 12
fmt.Println(l.Data()) // []int{2, 3, 4}
}
```

View File

@@ -26,11 +26,15 @@ import (
- [Data](#Data)
- [ValueOf](#ValueOf)
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [IndexOfFunc](#IndexOfFunc)
- [LastIndexOfFunc](#LastIndexOfFunc)
- [Push](#Push)
- [PopFirst](#PopFirst)
- [PopLast](#PopLast)
- [DeleteAt](#DeleteAt)
- [InsertAt](#InsertAt)
- [UpdateAt](#UpdateAt)
- [Equal](#Equal)
- [IsEmpty](#IsEmpty)
@@ -38,11 +42,14 @@ import (
- [Clone](#Clone)
- [Merge](#Merge)
- [Size](#Size)
- [Cap](#Cap)
- [Swap](#Swap)
- [Reverse](#Reverse)
- [Unique](#Unique)
- [Union](#Union)
- [Intersection](#Intersection)
- [SubList](#SubList)
- [DeleteIf](#DeleteIf)
<div STYLE="page-break-after: always;"></div>
@@ -192,6 +199,85 @@ func main() {
```
### <span id="LastIndexOf">LastIndexOf</span>
<p>返回列表中最后一次出现的值的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOf(value T) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOf(1)) // 3
fmt.Println(li.LastIndexOf(0)) //-1
}
```
### <span id="IndexOfFunc">IndexOfFunc</span>
<p>返回第一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) IndexOfFunc(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3})
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 1 })) //0
fmt.Println(li.IndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="LastIndexOfFunc">LastIndexOfFunc</span>
<p>返回最后一个符合函数条件的元素的索引。如果未找到,则返回-1</p>
<b>函数签名:</b>
```go
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
li := list.NewList([]int{1, 2, 3, 1})
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 1 })) // 3
fmt.Println(li.LastIndexOfFunc(func(a int) bool { return a == 0 })) //-1
}
```
### <span id="Push">Push</span>
<p>将值附加到列表末尾</p>
@@ -566,6 +652,34 @@ func main() {
### <span id="Cap">Cap</span>
<p>返回列表数据容量</p>
<b>函数签名:</b>
```go
func (l *List[T]) Cap() int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
data := make([]int, 0, 100)
li := list.NewList(data)
fmt.Println(li.Cap()) // 100
}
```
### <span id="Swap">Swap</span>
<p>交换列表中两个索引位置的值</p>
@@ -709,4 +823,60 @@ func main() {
fmt.Println(li3.Data()) //4
}
```
### <span id="SubList">SubList</span>
<p>SubList returns a sub list of the original list between the specified fromIndex, inclusive, and toIndex, exclusive.</p>
<b>函数签名:</b>
```go
func (l *List[T]) SubList(fromIndex, toIndex int) *List[T]
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 2, 3, 4, 5, 6})
fmt.Println(l.SubList(2, 5)) // []int{3, 4, 5}
}
```
### <span id="DeleteIf">DeleteIf</span>
<p>删除列表中所有符合函数调用函数返回true)的元素,返回删除元素的数量</p>
<b>函数签名:</b>
```go
func (l *List[T]) DeleteIf(f func(T) bool) int
```
<b>例子:</b>
```go
package main
import (
"fmt"
list "github.com/duke-git/lancet/v2/datastructure/list"
)
func main() {
l := list.NewList([]int{1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1})
fmt.Println(l.DeleteIf(func(a int) bool { return a == 1 })) // 12
fmt.Println(l.Data()) // []int{2, 3, 4}
}
```

View File

@@ -27,7 +27,7 @@ import (
- [Merge](#Merge)
- [Minus](#Minus)
- [Values](#Values)
- [Values](#Values)
- [IsDisjoint](#IsDisjoint)
<div STYLE="page-break-after: always;"></div>
@@ -305,7 +305,7 @@ func main() {
```
### <span id="IsDisjoint">IsDisjoint</span>
<p>Checks two 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>

View File

@@ -7,6 +7,8 @@ Package netutil contains functions to get net information and send http request.
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
@@ -31,11 +33,17 @@ import (
- [GetRequestPublicIp](#GetRequestPublicIp)
- [IsPublicIP](#IsPublicIP)
- [IsInternalIP](#IsInternalIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [HttpRequest](#HttpRequest)
- [HttpClient](#HttpClient)
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
@@ -335,8 +343,232 @@ func main() {
```
### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest is a struct used to abstract HTTP request entity.</p>
### <span id="HttpGet">HttpGet</span>
<b>Signature:</b>
```go
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
}
```
### <span id="HttpClient">HttpClient</span>
<p>HttpClient is a struct used to send HTTP request. It can be instanced with some configurations or none config.</p>
<b>Signature:</b>
```go
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
httpClientCfg := netutil.HttpClientConfig{
SSLEnabled: true,
HandshakeTimeout:10 * time.Second
}
httpClient := netutil.NewHttpClientWithConfig(&httpClientCfg)
}
```
### <span id="SendRequest">SendRequest</span>
<p>Use HttpClient to send HTTP request.</p>
<b>Signature:</b>
```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="DecodeResponse">DecodeResponse</span>
<p>Decode http response into target object.</p>
<b>Signature:</b>
```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
```
<b>Example:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="StructToUrlValues">StructToUrlValues</span>
<p>Convert struct to url values, only convert the field which is exported and has `json` tag.</p>
<b>Signature:</b>
```go
func StructToUrlValues(targetStruct any) url.Values
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 2,
}
todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1
fmt.Println(todoValues.Get("userId")) //2
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>Send http get request.</p>
<b>Signature:</b>
@@ -378,7 +610,7 @@ func main() {
### <span id="HttpPost">HttpPost</span>
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>Send http post request.</p>
<b>Signature:</b>
@@ -427,7 +659,7 @@ func main() {
### <span id="HttpPut">HttpPut</span>
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>Send http put request.</p>
<b>Signature:</b>
@@ -477,7 +709,7 @@ func main() {
### <span id="HttpDelete">HttpDelete</span>
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>Send http delete request.</p>
<b>Signature:</b>
@@ -516,7 +748,7 @@ func main() {
### <span id="HttpPatch">HttpPatch</span>
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>Send http patch request.</p>
<b>Signature:</b>

View File

@@ -6,6 +6,9 @@ netutil网络包支持获取ip地址发送http请求。
## 源码:
- [https://github.com/duke-git/lancet/blob/main/netutil/net.go](https://github.com/duke-git/lancet/blob/main/netutil/net.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http_client.go](https://github.com/duke-git/lancet/blob/main/netutil/http_client.go)
- [https://github.com/duke-git/lancet/blob/main/netutil/http.go](https://github.com/duke-git/lancet/blob/main/netutil/http.go)
<div STYLE="page-break-after: always;"></div>
@@ -30,11 +33,18 @@ import (
- [IsPublicIP](#IsPublicIP)
- [IsInternalIP](#IsInternalIP)
- [HttpGet](#HttpGet)
- [HttpDelete](#HttpDelete)
- [HttpPost](#HttpPost)
- [HttpPut](#HttpPut)
- [HttpPatch](#HttpPatch)
- [HttpRequest](#HttpRequest)
- [HttpClient](#HttpClient)
- [SendRequest](#SendRequest)
- [DecodeResponse](#DecodeResponse)
- [StructToUrlValues](#StructToUrlValues)
- [HttpGet<sup>Deprecated</sup>](#HttpGet)
- [HttpDelete<sup>Deprecated</sup>](#HttpDelete)
- [HttpPost<sup>Deprecated</sup>](#HttpPost)
- [HttpPut<sup>Deprecated</sup>](#HttpPut)
- [HttpPatch<sup>Deprecated</sup>](#HttpPatch)
- [ParseHttpResponse](#ParseHttpResponse)
<div STYLE="page-break-after: always;"></div>
@@ -334,8 +344,232 @@ func main() {
```
### <span id="HttpRequest">HttpRequest</span>
<p>HttpRequest用于抽象HTTP请求实体的结构</p>
### <span id="HttpGet">HttpGet</span>
<b>函数签名:</b>
```go
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
}
```
### <span id="HttpClient">HttpClient</span>
<p>HttpClient是用于发送HTTP请求的结构体。它可以用一些配置参数或无配置实例化.</p>
<b>函数签名:</b>
```go
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
func NewHttpClient() *HttpClient
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
httpClientCfg := netutil.HttpClientConfig{
SSLEnabled: true,
HandshakeTimeout:10 * time.Second
}
httpClient := netutil.NewHttpClientWithConfig(&httpClientCfg)
}
```
### <span id="SendRequest">SendRequest</span>
<p>HttpClient发送http请求</p>
<b>函数签名:</b>
```go
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error)
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="DecodeResponse">DecodeResponse</span>
<p>解析http响应体到目标结构体</p>
<b>函数签名:</b>
```go
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error
```
<b>例子:</b>
```go
package main
import (
"fmt"
"net"
"time"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
request := &netutil.HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := netutil.NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
fmt.Println(todo.Id) //1
}
```
### <span id="StructToUrlValues">StructToUrlValues</span>
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag.</p>
<b>函数签名:</b>
```go
func StructToUrlValues(targetStruct any) url.Values
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/netutil"
)
func main() {
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 2,
}
todoValues := netutil.StructToUrlValues(todoQuery)
fmt.Println(todoValues.Get("id")) //1
fmt.Println(todoValues.Get("userId")) //2
}
```
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
<p>发送http get请求</p>
<b>函数签名:</b>
@@ -377,7 +611,7 @@ func main() {
### <span id="HttpPost">HttpPost</span>
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
<p>发送http post请求</p>
<b>函数签名:</b>
@@ -426,7 +660,7 @@ func main() {
### <span id="HttpPut">HttpPut</span>
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
<p>发送http put请求</p>
<b>函数签名:</b>
@@ -438,7 +672,7 @@ func main() {
// params[3] http client类型必须是http.Client
func HttpPut(url string, params ...any) (*http.Response, error)
```
<b>Example:</b>
<b>例子:</b>
```go
package main
@@ -476,7 +710,7 @@ func main() {
### <span id="HttpDelete">HttpDelete</span>
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
<p>发送http delete请求</p>
<b>函数签名:</b>
@@ -515,7 +749,7 @@ func main() {
### <span id="HttpPatch">HttpPatch</span>
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
<p>发送http patch请求</p>
<b>函数签名:</b>

View File

@@ -20,6 +20,7 @@ import (
<div STYLE="page-break-after: always;"></div>
## Index
- [AppendIfAbsent](#AppendIfAbsent)
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
@@ -69,6 +70,33 @@ import (
## Documentation
### <span id="AppendIfAbsent">AppendIfAbsent</span>
<p>If slice doesn't contain the value, append it to the slice.</p>
<b>Signature:</b>
```go
func AppendIfAbsent[T comparable](slice []T, value T) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
strs := []string{"a", "b"}
res1 := slice.AppendIfAbsent(strs, "a")
fmt.Println(res1) //[]string{"a", "b"}
res2 := slice.AppendIfAbsent(strs, "cannot")
fmt.Println(res2"}
}
```
### <span id="Contain">Contain</span>
<p>Check if the value is in the slice or not.</p>

View File

@@ -20,6 +20,7 @@ import (
<div STYLE="page-break-after: always;"></div>
## 目录
- [AppendIfAbsent](#AppendIfAbsent)
- [Contain](#Contain)
- [ContainSubSlice](#ContainSubSlice)
- [Chunk](#Chunk)
@@ -69,6 +70,34 @@ import (
## 文档
### <span id="AppendIfAbsent">AppendIfAbsent</span>
<p>当前切片中不包含值时,将该值追加到切片中</p>
<b>函数签名:</b>
```go
func AppendIfAbsent[T comparable](slice []T, value T) []T
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
strs := []string{"a", "b"}
res1 := slice.AppendIfAbsent(strs, "a")
fmt.Println(res1) //[]string{"a", "b"}
res2 := slice.AppendIfAbsent(strs, "cannot")
fmt.Println(res2"}
}
```
### <span id="Contain">Contain</span>
<p>判断slice是否包含value</p>

View File

@@ -32,7 +32,7 @@ import (
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [SplitEx](#SplitEx)
- [Wrap](#Wrap)
@@ -430,13 +430,13 @@ func main() {
### <span id="ReverseStr">ReverseStr</span>
### <span id="Reverse">Reverse</span>
<p>Return string whose char order is reversed to the given string.</p>
<b>Signature:</b>
```go
func ReverseStr(s string) string
func Reverse(s string) string
```
<b>Example:</b>

View File

@@ -32,7 +32,7 @@ import (
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [ReverseStr](#ReverseStr)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [SplitEx](#SplitEx)
- [Wrap](#Wrap)
@@ -431,13 +431,13 @@ func main() {
### <span id="ReverseStr">ReverseStr</span>
### <span id="Reverse">Reverse</span>
<p>返回字符顺序与给定字符串相反的字符串</p>
<b>函数签名:</b>
```go
func ReverseStr(s string) string
func Reverse(s string) string
```
<b>例子:</b>

View File

@@ -47,6 +47,7 @@ import (
- [IsStrongPassword](#IsStrongPassword)
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
<div STYLE="page-break-after: always;"></div>
@@ -765,7 +766,7 @@ func main() {
### <span id="IsWeakPassword">IsWeakPassword</span>
<p>Check if the string is weak passwordonly letter or only number or letter + number
<p>Checks if the string is weak passwordonly letter or only number or letter + number
.</p>
<b>Signature:</b>
@@ -792,6 +793,36 @@ func main() {
### <span id="IsZeroValue">IsZeroValue</span>
<p>Checks if passed value is a zero value.</p>
<b>Signature:</b>
```go
func IsZeroValue(value any) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsZeroValue(nil)) //true
fmt.Println(validator.IsZeroValue(0)) //true
fmt.Println(validator.IsZeroValue("")) //true
fmt.Println(validator.IsZeroValue([]int)) //true
fmt.Println(validator.IsZeroValue(interface{})) //true
fmt.Println(validator.IsZeroValue("0")) //false
fmt.Println(validator.IsZeroValue("nil")) //false
}
```

View File

@@ -47,6 +47,7 @@ import (
- [IsStrongPassword](#IsStrongPassword)
- [IsUrl](#IsUrl)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
<div STYLE="page-break-after: always;"></div>
@@ -792,8 +793,31 @@ func main() {
### <span id="IsZeroValue">IsZeroValue</span>
<p>判断传入的参数值是否为零值</p>
<b>函数签名:</b>
```go
func IsZeroValue(value any) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
)
func main() {
fmt.Println(validator.IsZeroValue(nil)) //true
fmt.Println(validator.IsZeroValue(0)) //true
fmt.Println(validator.IsZeroValue("")) //true
fmt.Println(validator.IsZeroValue([]int)) //true
fmt.Println(validator.IsZeroValue(interface{})) //true
fmt.Println(validator.IsZeroValue("0")) //false
fmt.Println(validator.IsZeroValue("nil")) //false
}
```

View File

@@ -46,7 +46,7 @@ import (
)
func main() {
_, err := strconv.Atoi("4o2")
_, err := strconv.Atoi("4o2")
defer func() {
v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()

View File

@@ -46,7 +46,7 @@ import (
)
func main() {
_, err := strconv.Atoi("4o2")
_, err := strconv.Atoi("4o2")
defer func() {
v := recover()
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()

View File

@@ -116,7 +116,7 @@ func TestDebounced(t *testing.T) {
}
func TestSchedule(t *testing.T) {
assert := internal.NewAssert(t, "TestSchedule")
// assert := internal.NewAssert(t, "TestSchedule")
var res []string
appendStr := func(s string) {
@@ -127,6 +127,10 @@ func TestSchedule(t *testing.T) {
time.Sleep(5 * time.Second)
close(stop)
expected := []string{"*", "*", "*", "*", "*"}
assert.Equal(expected, res)
t.Log(res)
// todo: in github action, for now, this test is not working sometimes
// res maybe [* * * * *] or [* * * * * *]
// expected := []string{"*", "*", "*", "*", "*"}
// assert.Equal(expected, res)
}

228
netutil/http_client.go Normal file
View File

@@ -0,0 +1,228 @@
package netutil
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
"strings"
"time"
"github.com/duke-git/lancet/v2/slice"
)
// HttpRequest struct is a composed http request
type HttpRequest struct {
RawURL string
Method string
Headers http.Header
QueryParams url.Values
FormData url.Values
Body []byte
}
// HttpClientConfig contains some configurations for http client
type HttpClientConfig struct {
SSLEnabled bool
TLSConfig *tls.Config
Compressed bool
HandshakeTimeout time.Duration
ResponseTimeout time.Duration
Verbose bool
}
// defaultHttpClientConfig defalut client config
var defaultHttpClientConfig = &HttpClientConfig{
Compressed: false,
HandshakeTimeout: 20 * time.Second,
ResponseTimeout: 40 * time.Second,
}
// HttpClient is used for sending http request
type HttpClient struct {
*http.Client
TLS *tls.Config
Request *http.Request
Config HttpClientConfig
}
// NewHttpClient make a HttpClient instance
func NewHttpClient() *HttpClient {
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
DisableCompression: !defaultHttpClientConfig.Compressed,
},
},
Config: *defaultHttpClientConfig,
}
return client
}
// NewHttpClientWithConfig make a HttpClient instance with pass config
func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
if config == nil {
config = defaultHttpClientConfig
}
client := &HttpClient{
Client: &http.Client{
Transport: &http.Transport{
TLSHandshakeTimeout: config.HandshakeTimeout,
ResponseHeaderTimeout: config.ResponseTimeout,
DisableCompression: !config.Compressed,
},
},
Config: *config,
}
if config.SSLEnabled {
client.TLS = config.TLSConfig
}
return client
}
// SendRequest send http request
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) {
err := validateRequest(request)
if err != nil {
return nil, err
}
rawUrl := request.RawURL
req, err := http.NewRequest(request.Method, rawUrl, bytes.NewBuffer(request.Body))
if err != nil {
return nil, err
}
client.setTLS(rawUrl)
client.setHeader(req, request.Headers)
client.setQueryParam(req, rawUrl, request.QueryParams)
if request.FormData != nil {
client.setFormData(req, request.FormData)
}
client.Request = req
resp, err := client.Client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
// DecodeResponse decode response into target object
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
if resp == nil {
return errors.New("invalid target param")
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(target)
}
// setTLS set http client transport TLSClientConfig
func (client *HttpClient) setTLS(rawUrl string) {
if strings.HasPrefix(rawUrl, "https") {
if transport, ok := client.Client.Transport.(*http.Transport); ok {
transport.TLSClientConfig = client.TLS
}
}
}
// setHeader set http rquest header
func (client *HttpClient) setHeader(req *http.Request, headers http.Header) {
if headers == nil {
headers = make(http.Header)
}
if _, ok := headers["Accept"]; !ok {
headers["Accept"] = []string{"*/*"}
}
if _, ok := headers["Accept-Encoding"]; !ok && client.Config.Compressed {
headers["Accept-Encoding"] = []string{"deflate, gzip"}
}
req.Header = headers
}
// setQueryParam set http request query string param
func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryParam url.Values) error {
if queryParam != nil {
if !strings.Contains(reqUrl, "?") {
reqUrl = reqUrl + "?" + queryParam.Encode()
} else {
reqUrl = reqUrl + "&" + queryParam.Encode()
}
u, err := url.Parse(reqUrl)
if err != nil {
return err
}
req.URL = u
}
return nil
}
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
formData := []byte(values.Encode())
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
}
// validateRequest check if a request has url, and valid method.
func validateRequest(req *HttpRequest) error {
if req.RawURL == "" {
return errors.New("invalid request url")
}
// common HTTP methods
methods := []string{"GET", "POST", "PUT", "DELETE", "PATCH",
"HEAD", "CONNECT", "OPTIONS", "TRACE"}
if !slice.Contain(methods, strings.ToUpper(req.Method)) {
return errors.New("invalid request method")
}
return nil
}
// StructToUrlValues convert struct to url valuse,
// only convert the field which is exported and has `json` tag
func StructToUrlValues(targetStruct any) url.Values {
rv := reflect.ValueOf(targetStruct)
rt := reflect.TypeOf(targetStruct)
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
panic(fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", targetStruct))
}
result := url.Values{}
fieldNum := rt.NumField()
pattern := `^[A-Z]`
regex := regexp.MustCompile(pattern)
for i := 0; i < fieldNum; i++ {
name := rt.Field(i).Name
tag := rt.Field(i).Tag.Get("json")
if regex.MatchString(name) && tag != "" {
result.Add(tag, fmt.Sprintf("%v", rv.Field(i).Interface()))
}
}
return result
}

View File

@@ -0,0 +1,95 @@
package netutil
import (
"io/ioutil"
"log"
"net/http"
"net/url"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestHttpClient_Get(t *testing.T) {
assert := internal.NewAssert(t, "TestHttpClient_Get")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
Method: "GET",
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
type Todo struct {
UserId int `json:"userId"`
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
assert.Equal(1, todo.Id)
}
func TestHttpClent_Post(t *testing.T) {
header := http.Header{}
header.Add("Content-Type", "multipart/form-data")
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "testItem")
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "POST",
Headers: header,
FormData: postData,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
func TestStructToUrlValues(t *testing.T) {
assert := internal.NewAssert(t, "TestStructToUrlValues")
type TodoQuery struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
todoQuery := TodoQuery{
Id: 1,
UserId: 1,
}
todoValues := StructToUrlValues(todoQuery)
assert.Equal("1", todoValues.Get("id"))
assert.Equal("1", todoValues.Get("userId"))
request := &HttpRequest{
RawURL: "https://jsonplaceholder.typicode.com/todos",
Method: "GET",
QueryParams: todoValues,
}
httpClient := NewHttpClient()
resp, err := httpClient.SendRequest(request)
if err != nil || resp.StatusCode != 200 {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", string(body))
}

View File

@@ -18,7 +18,6 @@ func TestHttpGet(t *testing.T) {
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
@@ -40,7 +39,6 @@ func TestHttpPost(t *testing.T) {
resp, err := HttpPost(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -67,7 +65,6 @@ func TestHttpPostFormData(t *testing.T) {
resp, err := HttpPost(apiUrl, header, postData, nil)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -89,7 +86,6 @@ func TestHttpPut(t *testing.T) {
resp, err := HttpPut(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -111,7 +107,6 @@ func TestHttpPatch(t *testing.T) {
resp, err := HttpPatch(url, header, nil, bodyParams)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -122,7 +117,6 @@ func TestHttpDelete(t *testing.T) {
resp, err := HttpDelete(url)
if err != nil {
log.Fatal(err)
t.FailNow()
}
body, _ := ioutil.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
@@ -148,7 +142,6 @@ func TestParseResponse(t *testing.T) {
resp, err := HttpGet(url, header)
if err != nil {
log.Fatal(err)
t.FailNow()
}
type Todo struct {
@@ -162,7 +155,6 @@ func TestParseResponse(t *testing.T) {
err = ParseHttpResponse(resp, toDoResp)
if err != nil {
log.Fatal(err)
t.FailNow()
}
t.Log("response: ", toDoResp)
}

View File

@@ -14,13 +14,13 @@ import (
// Contain check if the value is in the slice or not
func Contain[T comparable](slice []T, value T) bool {
set := make(map[T]struct{}, len(slice))
for _, v := range slice {
if v == value {
return true
}
set[v] = struct{}{}
}
return false
_, ok := set[value]
return ok
}
// ContainSubSlice check if the slice contain subslice or not
@@ -851,3 +851,11 @@ func ToSlice[T any](value ...T) []T {
}
return out
}
// AppendIfAbsent only absent append the value
func AppendIfAbsent[T comparable](slice []T, value T) []T {
if !Contain(slice, value) {
slice = append(slice, value)
}
return slice
}

View File

@@ -609,3 +609,11 @@ func TestToSlicePointer(t *testing.T) {
assert.Equal([]*string{&str1}, ToSlicePointer(str1))
assert.Equal([]*string{&str1, &str2}, ToSlicePointer(str1, str2))
}
func TestAppendIfAbsent(t *testing.T) {
assert := internal.NewAssert(t, "TestAppendIfAbsent")
str1 := []string{"a", "b"}
assert.Equal([]string{"a", "b"}, AppendIfAbsent(str1, "a"))
assert.Equal([]string{"a", "b", "c"}, AppendIfAbsent(str1, "c"))
}

View File

@@ -208,8 +208,8 @@ func IsString(v any) bool {
}
}
// ReverseStr return string whose char order is reversed to the given string
func ReverseStr(s string) string {
// Reverse return string whose char order is reversed to the given string
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]

View File

@@ -143,11 +143,11 @@ func TestIsString(t *testing.T) {
assert.Equal(false, IsString([]string{}))
}
func TestReverseStr(t *testing.T) {
assert := internal.NewAssert(t, "TestReverseStr")
func TestReverse(t *testing.T) {
assert := internal.NewAssert(t, "TestReverse")
assert.Equal("cba", ReverseStr("abc"))
assert.Equal("54321", ReverseStr("12345"))
assert.Equal("cba", Reverse("abc"))
assert.Equal("54321", Reverse("12345"))
}
func TestWrap(t *testing.T) {

View File

@@ -8,6 +8,7 @@ import (
"encoding/json"
"net"
"net/url"
"reflect"
"regexp"
"strconv"
"strings"
@@ -253,3 +254,32 @@ func IsWeakPassword(password string) bool {
return (num || letter) && !special
}
// IsZeroValue checks if value is a zero value
func IsZeroValue(value any) bool {
if value == nil {
return true
}
rv := reflect.ValueOf(value)
if !rv.IsValid() {
return true
}
switch rv.Kind() {
case reflect.String:
return rv.Len() == 0
case reflect.Bool:
return !rv.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return rv.Uint() == 0
case reflect.Float32, reflect.Float64:
return rv.Float() == 0
case reflect.Ptr, reflect.Chan, reflect.Func, reflect.Interface, reflect.Slice, reflect.Map:
return rv.IsNil()
}
return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface())
}

View File

@@ -1,7 +1,9 @@
package validator
import (
"fmt"
"testing"
"time"
"github.com/duke-git/lancet/v2/internal"
)
@@ -279,3 +281,110 @@ func TestIsWeakPassword(t *testing.T) {
assert.Equal(true, IsWeakPassword("abcABC123"))
assert.Equal(false, IsWeakPassword("abc123@#$"))
}
func TestIsZeroValue(t *testing.T) {
assert := internal.NewAssert(t, "TestIsZeroValue")
var (
zeroPtr *string
zeroSlice []int
zeroFunc func() string
zeroMap map[string]string
nilIface interface{}
zeroIface fmt.Formatter
)
zeroValues := []interface{}{
nil,
false,
0,
int8(0),
int16(0),
int32(0),
int64(0),
uint(0),
uint8(0),
uint16(0),
uint32(0),
uint64(0),
0.0,
float32(0.0),
float64(0.0),
"",
// func
zeroFunc,
// array / slice
[0]int{},
zeroSlice,
// map
zeroMap,
// interface
nilIface,
zeroIface,
// pointer
zeroPtr,
// struct
time.Time{},
}
for _, value := range zeroValues {
assert.Equal(true, IsZeroValue(value))
}
var nonZeroIface fmt.Stringer = time.Now()
nonZeroValues := []interface{}{
// bool
true,
// int
1,
int8(1),
int16(1),
int32(1),
int64(1),
uint8(1),
uint16(1),
uint32(1),
uint64(1),
// float
1.0,
float32(1.0),
float64(1.0),
// string
"test",
// func
time.Now,
// array / slice
[]int{},
[]int{42},
[1]int{42},
// map
make(map[string]string, 1),
// interface
nonZeroIface,
// pointer
&nonZeroIface,
// struct
time.Now(),
}
for _, value := range nonZeroValues {
assert.Equal(false, IsZeroValue(value))
}
}