mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
13
Commits
3d1bd08434
...
v2.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
036847577d | ||
|
|
d21edd1cde | ||
|
|
c58c50327c | ||
|
|
9bfdc686f8 | ||
|
|
5ca8f6ef6f | ||
|
|
a54d4c79a0 | ||
|
|
f7b54986aa | ||
|
|
92fae4273b | ||
|
|
0d29f5437a | ||
|
|
e95d7c82cd | ||
|
|
e138043289 | ||
|
|
aabfcb7bde | ||
|
|
0b5e884371 |
@@ -30,7 +30,7 @@ We are excited that you are interested in contributing to lancet. Before submitt
|
|||||||
|
|
||||||
- Before submitting a PR, please execute the unit test command: `go test -v ./...` to ensure that all unit test tasks should pass.
|
- Before submitting a PR, please execute the unit test command: `go test -v ./...` to ensure that all unit test tasks should pass.
|
||||||
|
|
||||||
- Make sure PRs are created to `rc` branch instead of `master` branch.
|
- Make sure PRs are created to `rc` branch instead of other branch.
|
||||||
|
|
||||||
- If your PR fixes a bug, please provide a description about the related bug.
|
- If your PR fixes a bug, please provide a description about the related bug.
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.2. </b>
|
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.4.3. </b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||||
@@ -729,6 +729,10 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||||
- **<big>ReadFile</big>** : read file or url.
|
- **<big>ReadFile</big>** : read file or url.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ReadFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ReadFile)]
|
||||||
|
- **<big>ChunkRead</big>** : reads a block from the file at the specified offset and returns all lines within the block.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ChunkRead)]
|
||||||
|
- **<big>ParallelChunkRead</big>** : reads the file in parallel and send each chunk of lines to the specified channel.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#ParallelChunkRead)]
|
||||||
|
|
||||||
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -791,11 +795,25 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
[[play](https://go.dev/play/p/hbON-Xeyn5N)]
|
||||||
- **<big>Pipeline</big>** : takes a list of functions and returns a function whose param will be passed into the functions one by one.
|
- **<big>Pipeline</big>** : takes a list of functions and returns a function whose param will be passed into the functions one by one.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Pipeline)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Pipeline)]
|
||||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
- **<big>AcceptIf</big>** : returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#AcceptIf)]
|
||||||
|
- **<big>And</big>** : returns a composed predicate that represents the logical AND of a list of predicates.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#And)]
|
||||||
|
- **<big>Or</big>** : returns a composed predicate that represents the logical OR of a list of predicates.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Or)]
|
||||||
|
- **<big>Negate</big>** : returns a predicate that represents the logical negation of this predicate.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Negate)]
|
||||||
|
- **<big>Nor</big>** : returns a composed predicate that represents the logical NOR of a list of predicates.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Nor)]
|
||||||
|
- **<big>Nand</big>** : returns a composed predicate that represents the logical Nand of a list of predicates.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Nand)]
|
||||||
|
- **<big>Xnor</big>** : returns a composed predicate that represents the logical XNOR of a list of predicates.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Xnor)]
|
||||||
- **<big>Watcher</big>** : Watcher is used for record code execution time. can start/stop/reset the watch timer. get the elapsed time of function execution.
|
- **<big>Watcher</big>** : Watcher is used for record code execution time. can start/stop/reset the watch timer. get the elapsed time of function execution.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</a></h3>
|
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -939,6 +957,14 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>CeilToFloat</big>** : round float up n decimal places.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#CeilToFloat)]
|
||||||
|
- **<big>CeilToString</big>** : round float up n decimal places, then conver to string.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#CeilToString)]
|
||||||
|
- **<big>FloorToFloat</big>** : round float down n decimal places.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#FloorToFloat)]
|
||||||
|
- **<big>FloorToString</big>** : round float down n decimal places, then conver to string.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#FloorToString)]
|
||||||
- **<big>Range</big>** : Creates a slice of numbers from start with specified count, element step is 1.
|
- **<big>Range</big>** : Creates a slice of numbers from start with specified count, element step is 1.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Range)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Range)]
|
||||||
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
||||||
@@ -978,6 +1004,9 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>Abs</big>** : returns the absolute value of param number.
|
- **<big>Abs</big>** : returns the absolute value of param number.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Sum)]
|
||||||
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
|
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
|
||||||
|
- **<big>Div</big>** : returns the result of x divided by y.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Div)]
|
||||||
|
|
||||||
|
|
||||||
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1147,6 +1176,16 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
- **<big>RetryTimes</big>** : set times of retry.
|
- **<big>RetryTimes</big>** : set times of retry.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryTimes)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryTimes)]
|
||||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||||
|
- **<big>BackoffStrategy</big>** : An interface that defines a method for calculating backoff intervals.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#BackoffStrategy)]
|
||||||
|
- **<big>RetryWithCustomBackoff</big>** : set abitary custom backoff strategy.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithCustomBackoff)]
|
||||||
|
- **<big>RetryWithLinearBackoff</big>** : set linear strategy backoff.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithLinearBackoff)]
|
||||||
|
- **<big>RetryWithExponentialWithJitterBackoff</big>** : set exponential strategy backoff.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
@@ -1621,7 +1660,8 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/HzLC9vsTwkf)]
|
[[play](https://go.dev/play/p/HzLC9vsTwkf)]
|
||||||
- **<big>SubInBetween</big>** : return substring between the start and end position(excluded) of source string.
|
- **<big>SubInBetween</big>** : return substring between the start and end position(excluded) of source string.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#SubInBetween)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#SubInBetween)]
|
||||||
|
- **<big>HammingDistance</big>** : calculates the Hamming distance between two strings.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#HammingDistance)]
|
||||||
|
|
||||||
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. <a href="#index">index</a></h3>
|
||||||
|
|
||||||
|
|||||||
+47
-3
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.2。</b>
|
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.3。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||||
@@ -100,6 +100,7 @@ func main() {
|
|||||||
- [Validator](#user-content-validator)
|
- [Validator](#user-content-validator)
|
||||||
- [Xerror](#user-content-xerror)
|
- [Xerror](#user-content-xerror)
|
||||||
|
|
||||||
|
|
||||||
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
<h3 id="algorithm"> 1. algorithm 包实现一些基本查找和排序算法。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -727,6 +728,12 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
|||||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||||
- **<big>ReadFile</big>** : 读取文件或者URL。
|
- **<big>ReadFile</big>** : 读取文件或者URL。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadFile)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ReadFile)]
|
||||||
|
- **<big>ChunkRead</big>** : 从文件的指定偏移读取块并返回块内所有行。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ChunkRead)]
|
||||||
|
- **<big>ParallelChunkRead</big>** : 并行读取文件并将每个块的行发送到指定通道。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#ParallelChunkRead)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
<h3 id="formatter"> 10. formatter 格式化器包含一些数据格式化处理方法。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -790,6 +797,20 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
- **<big>Pipeline</big>** : 从右至左执行函数列表。
|
- **<big>Pipeline</big>** : 从右至左执行函数列表。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Pipeline)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Pipeline)]
|
||||||
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
[[play](https://go.dev/play/p/mPdUVvj6HD6)]
|
||||||
|
- **<big>AcceptIf</big>** : AcceptIf函数会返回另一个函数,该函数的签名与apply函数相同,但同时还会包含一个布尔值来表示成功或失败。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#AcceptIf)]
|
||||||
|
- **<big>And</big>** : 返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑and操作。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#And)]
|
||||||
|
- **<big>Or</big>** : 返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑or操作。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Or)]
|
||||||
|
- **<big>Negate</big>** : 返回一个谓词函数,该谓词函数表示当前谓词的逻辑否定。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Negate)]
|
||||||
|
- **<big>Nor</big>** : 返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑非或nor的操作。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Nor)]
|
||||||
|
- **<big>Nand</big>** : 返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑非与nand的操作。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Nand)]
|
||||||
|
- **<big>Xnor</big>** : 返回一个复合谓词判断函数,该判断函数表示一组谓词的逻辑异或xnor的操作。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Xnor)]
|
||||||
- **<big>Watcher</big>** : Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
|
- **<big>Watcher</big>** : Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Watcher)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Watcher)]
|
||||||
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
|
||||||
@@ -937,6 +958,14 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>CeilToFloat</big>** : 向上舍入(进一法),保留n位小数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#CeilToFloat)]
|
||||||
|
- **<big>CeilToString</big>** : 向上舍入(进一法),保留n位小数,返回字符串。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#CeilToString)]
|
||||||
|
- **<big>FloorToFloat</big>** : 向下舍入(去尾法),保留n位小数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#FloorToFloat)]
|
||||||
|
- **<big>FloorToString</big>** : 向下舍入(去尾法),保留n位小数,返回字符串。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#FloorToString)]
|
||||||
- **<big>Range</big>** : 根据指定的起始值和数量,创建一个数字切片。
|
- **<big>Range</big>** : 根据指定的起始值和数量,创建一个数字切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Range)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Range)]
|
||||||
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
[[play](https://go.dev/play/p/9ke2opxa8ZP)]
|
||||||
@@ -976,6 +1005,10 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>Abs</big>** : 求绝对值。
|
- **<big>Abs</big>** : 求绝对值。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Sum)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Sum)]
|
||||||
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
|
[[play](https://go.dev/play/p/fsyBh1Os-1d)]
|
||||||
|
- **<big>Div</big>** : 除法运算。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Div)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
<h3 id="netutil"> 14. netutil 网络包支持获取 ip 地址,发送 http 请求。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1143,6 +1176,16 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
|
- **<big>RetryTimes</big>** : 设置重试次数,默认 5。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryTimes)]
|
||||||
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
[[play](https://go.dev/play/p/ssfVeU2SwLO)]
|
||||||
|
- **<big>BackoffStrategy</big>** : 定义计算退避间隔的方法的接口。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#BackoffStrategy)]
|
||||||
|
- **<big>RetryWithCustomBackoff</big>** : 设置自定义退避策略。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithCustomBackoff)]
|
||||||
|
- **<big>RetryWithLinearBackoff</big>** : 设置线性策略退避。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithLinearBackoff)]
|
||||||
|
- **<big>RetryWithExponentialWithJitterBackoff</big>** : 设置指数策略退避。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
<h3 id="slice"> 18. slice 包含操作切片的方法集合。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
@@ -1620,7 +1663,8 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/HzLC9vsTwkf)]
|
[[play](https://go.dev/play/p/HzLC9vsTwkf)]
|
||||||
- **<big>SubInBetween</big>** : 获取字符串中指定的起始字符串start和终止字符串end直接的子字符串。
|
- **<big>SubInBetween</big>** : 获取字符串中指定的起始字符串start和终止字符串end直接的子字符串。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#SubInBetween)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#SubInBetween)]
|
||||||
|
- **<big>HammingDistance</big>** : 计算两个字符串之间的汉明距离。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#HammingDistance)]
|
||||||
|
|
||||||
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
<h3 id="system"> 22. system 包含 os, runtime, shell command 的相关函数。 <a href="#index">回到目录</a></h3>
|
||||||
|
|
||||||
|
|||||||
@@ -466,12 +466,6 @@ func TestGbkToUtf8(t *testing.T) {
|
|||||||
assert.Equal("hello", string(utf8Data))
|
assert.Equal("hello", string(utf8Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeBase64(data []byte) ([]byte, error) {
|
|
||||||
buf := make([]byte, base64.StdEncoding.DecodedLen(len(data)))
|
|
||||||
n, err := base64.StdEncoding.Decode(buf, data)
|
|
||||||
return buf[:n], err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToStdBase64(t *testing.T) {
|
func TestToStdBase64(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
assert := internal.NewAssert(t, "TestToStdBase64")
|
assert := internal.NewAssert(t, "TestToStdBase64")
|
||||||
|
|||||||
+134
-134
@@ -903,52 +903,52 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
afterEncode := convertor.ToStdBase64(nil)
|
afterEncode := convertor.ToStdBase64(nil)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
afterEncode = convertor.ToStdBase64("")
|
afterEncode = convertor.ToStdBase64("")
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToStdBase64(stringVal)
|
afterEncode = convertor.ToStdBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToStdBase64(intVal)
|
afterEncode = convertor.ToStdBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToStdBase64(mapVal)
|
afterEncode = convertor.ToStdBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToStdBase64(floatVal)
|
afterEncode = convertor.ToStdBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToStdBase64(boolVal)
|
afterEncode = convertor.ToStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToStdBase64(errVal)
|
afterEncode = convertor.ToStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
// MTIzLjQ1Ng==
|
// MTIzLjQ1Ng==
|
||||||
// dHJ1ZQ==
|
// dHJ1ZQ==
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -975,49 +975,49 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
afterEncode := convertor.ToUrlBase64(nil)
|
afterEncode := convertor.ToUrlBase64(nil)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToUrlBase64(stringVal)
|
afterEncode = convertor.ToUrlBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToUrlBase64(intVal)
|
afterEncode = convertor.ToUrlBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToUrlBase64(mapVal)
|
afterEncode = convertor.ToUrlBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToUrlBase64(floatVal)
|
afterEncode = convertor.ToUrlBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToUrlBase64(boolVal)
|
afterEncode = convertor.ToUrlBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToUrlBase64(errVal)
|
afterEncode = convertor.ToUrlBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
// MTIzLjQ1Ng==
|
// MTIzLjQ1Ng==
|
||||||
// dHJ1ZQ==
|
// dHJ1ZQ==
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1044,45 +1044,45 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToRawStdBase64(stringVal)
|
afterEncode = convertor.ToRawStdBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToRawStdBase64(intVal)
|
afterEncode = convertor.ToRawStdBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToRawStdBase64(mapVal)
|
afterEncode = convertor.ToRawStdBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToRawStdBase64(floatVal)
|
afterEncode = convertor.ToRawStdBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToRawStdBase64(boolVal)
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToRawStdBase64(errVal)
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
// MTIzLjQ1Ng
|
// MTIzLjQ1Ng
|
||||||
// dHJ1ZQ
|
// dHJ1ZQ
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1108,44 +1108,44 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToRawUrlBase64(intVal)
|
afterEncode = convertor.ToRawUrlBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToRawStdBase64(boolVal)
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToRawStdBase64(errVal)
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
// MTIzLjQ1Ng
|
// MTIzLjQ1Ng
|
||||||
// dHJ1ZQ
|
// dHJ1ZQ
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -50,6 +50,8 @@ import (
|
|||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
- [ReadFile](#ReadFile)
|
- [ReadFile](#ReadFile)
|
||||||
|
- [ChunkRead](#ChunkRead)
|
||||||
|
- [ParallelChunkRead](#ParallelChunkRead)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -955,9 +957,123 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(dat))
|
fmt.Println(string(dat))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// User-agent: *
|
// User-agent: *
|
||||||
// Disallow: /deny
|
// Disallow: /deny
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ChunkRead">ChunkRead</span>
|
||||||
|
|
||||||
|
<p>从文件的指定偏移读取块并返回块内所有行。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ChunkRead(file *os.File, offset int64, size int, bufPool *sync.Pool) ([]string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100
|
||||||
|
|
||||||
|
// test1.csv file content:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
filePath := "./testdata/test1.csv" // 替换为你的文件路径
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 0, defaultChunkSizeMB*mb)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines, err := fileutil.ChunkRead(f, 0, 100, &bufPool)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(lines[0])
|
||||||
|
fmt.Println(lines[1])
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParallelChunkRead">ParallelChunkRead</span>
|
||||||
|
|
||||||
|
<p>并行读取文件并将每个块的行发送到指定通道。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// filePath:文件路径
|
||||||
|
// chunkSizeMB: 分块的大小(单位MB,设置为0时使用默认100MB),设置过大反而不利,视情调整
|
||||||
|
// maxGoroutine: 并发读取分块的数量,设置为0时使用CPU核心数
|
||||||
|
// linesCh: 用于接收返回结果的通道。
|
||||||
|
func ParallelChunkRead(filePath string, linesCh chan<- []string, chunkSizeMB, maxGoroutine int) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100 // 默认值
|
||||||
|
|
||||||
|
numParsers := runtime.NumCPU()
|
||||||
|
|
||||||
|
linesCh := make(chan []string, numParsers)
|
||||||
|
|
||||||
|
// test1.csv file content:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
filePath := "./testdata/test1.csv"
|
||||||
|
|
||||||
|
go fileutil.ParallelChunkRead(filePath, linesCh, defaultChunkSizeMB, numParsers)
|
||||||
|
|
||||||
|
var totalLines int
|
||||||
|
for lines := range linesCh {
|
||||||
|
totalLines += len(lines)
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(totalLines)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
// 2
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -39,6 +39,8 @@ import (
|
|||||||
- [Nor](#Nor)
|
- [Nor](#Nor)
|
||||||
- [Xnor](#Xnor)
|
- [Xnor](#Xnor)
|
||||||
- [Nand](#Nand)
|
- [Nand](#Nand)
|
||||||
|
- [AcceptIf](#AcceptIf)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -638,4 +640,55 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AcceptIf">AcceptIf</span>
|
||||||
|
|
||||||
|
<p>AcceptIf函数会返回另一个函数,该函数的签名与 apply 函数相同,但同时还会包含一个布尔值来表示成功或失败。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
adder := AcceptIf(
|
||||||
|
And(
|
||||||
|
func(x int) bool {
|
||||||
|
return x > 10
|
||||||
|
}, func(x int) bool {
|
||||||
|
return x%2 == 0
|
||||||
|
}),
|
||||||
|
func(x int) int {
|
||||||
|
return x + 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result, ok := adder(20)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
result, ok = adder(21)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 21
|
||||||
|
// true
|
||||||
|
// 0
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -34,6 +34,10 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [CeilToFloat](#CeilToFloat)
|
||||||
|
- [CeilToString](#CeilToString)
|
||||||
|
- [FloorToFloat](#FloorToFloat)
|
||||||
|
- [FloorToString](#FloorToString)
|
||||||
- [Range](#Range)
|
- [Range](#Range)
|
||||||
- [RangeWithStep](#RangeWithStep)
|
- [RangeWithStep](#RangeWithStep)
|
||||||
- [AngleToRadian](#AngleToRadian)
|
- [AngleToRadian](#AngleToRadian)
|
||||||
@@ -47,6 +51,7 @@ import (
|
|||||||
- [Log](#Log)
|
- [Log](#Log)
|
||||||
- [Sum](#Sum)
|
- [Sum](#Sum)
|
||||||
- [Abs](#Abs)
|
- [Abs](#Abs)
|
||||||
|
- [Div](#Div)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -493,6 +498,150 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToFloat">CeilToFloat</span>
|
||||||
|
|
||||||
|
<p>向上舍入(进一法),保留n位小数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToFloat[T constraints.Float | constraints.Integer](x T, n int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToString">CeilToString</span>
|
||||||
|
|
||||||
|
<p>向上舍入(进一法),保留n位小数,返回字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToString(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToString(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToFloat">FloorToFloat</span>
|
||||||
|
|
||||||
|
<p>向下舍入(去尾法),保留n位小数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToString">FloorToString</span>
|
||||||
|
|
||||||
|
<p>向下舍入(去尾法),保留n位小数,返回字符串。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToString(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToString(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Range">Range</span>
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
<p>根据指定的起始值和数量,创建一个数字切片。</p>
|
<p>根据指定的起始值和数量,创建一个数字切片。</p>
|
||||||
@@ -965,16 +1114,51 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
result1 := Abs(-1)
|
result1 := Abs(-1)
|
||||||
result2 := Abs(-0.1)
|
result2 := Abs(-0.1)
|
||||||
result3 := Abs(float32(0.2))
|
result3 := Abs(float32(0.2))
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
fmt.Println(result3)
|
fmt.Println(result3)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// 0.1
|
// 0.1
|
||||||
// 0.2
|
// 0.2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Div">Div</span>
|
||||||
|
|
||||||
|
<p>除法运算.</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Div[T constraints.Float | constraints.Integer](x T, y T) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Div(9, 4)
|
||||||
|
result2 := mathutil.Div(1, 2)
|
||||||
|
result3 := mathutil.Div(0, 666)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
// Output:
|
||||||
|
// 2.25
|
||||||
|
// 0.5
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -27,6 +27,10 @@ import (
|
|||||||
- [RetryFunc](#RetryFunc)
|
- [RetryFunc](#RetryFunc)
|
||||||
- [RetryDuration](#RetryDuration)
|
- [RetryDuration](#RetryDuration)
|
||||||
- [RetryTimes](#RetryTimes)
|
- [RetryTimes](#RetryTimes)
|
||||||
|
- [BackoffStrategy](#BackoffStrategy)
|
||||||
|
- [RetryWithCustomBackoff](#RetryWithCustomBackoff)
|
||||||
|
- [RetryWithLinearBackoff](#RetryWithLinearBackoff)
|
||||||
|
- [RetryWithExponentialWithJitterBackoff](#RetryWithExponentialWithJitterBackoff)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -260,3 +264,201 @@ func main() {
|
|||||||
// 3
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="BackoffStrategy">BackoffStrategy</span>
|
||||||
|
|
||||||
|
<p>定义计算退避间隔的方法的接口。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// BackoffStrategy is an interface that defines a method for calculating backoff intervals.
|
||||||
|
type BackoffStrategy interface {
|
||||||
|
// CalculateInterval returns the time.Duration after which the next retry attempt should be made.
|
||||||
|
CalculateInterval() time.Duration
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExampleCustomBackoffStrategy struct {
|
||||||
|
interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||||
|
return c.interval + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&示例CustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RetryWithCustomBackoff">RetryWithCustomBackoff</span>
|
||||||
|
|
||||||
|
<p>设置自定义退避策略。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExampleCustomBackoffStrategy struct {
|
||||||
|
interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||||
|
return c.interval + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&示例CustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RetryWithLinearBackoff">RetryWithLinearBackoff</span>
|
||||||
|
|
||||||
|
<p>设置线性策略退避。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithLinearBackoff(interval time.Duration) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry.Retry(increaseNumber, retry.RetryWithLinearBackoff(time.Microsecond*50))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RetryWithExponentialWithJitterBackoff">RetryWithExponentialWithJitterBackoff</span>
|
||||||
|
|
||||||
|
<p>设置指数策略退避。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithExponentialWithJitterBackoff(interval time.Duration, base uint64, maxJitter time.Duration) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry.Retry(increaseNumber, retry.RetryWithExponentialWithJitterBackoff(time.Microsecond*50, 2, time.Microsecond*25))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import (
|
|||||||
- [ContainsAny](#ContainsAny)
|
- [ContainsAny](#ContainsAny)
|
||||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||||
- [SubInBetween](#SubInBetween)
|
- [SubInBetween](#SubInBetween)
|
||||||
|
- [HammingDistance](#HammingDistance)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1495,4 +1496,36 @@ func main() {
|
|||||||
// abc
|
// abc
|
||||||
// bc
|
// bc
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HammingDistance">HammingDistance</span>
|
||||||
|
|
||||||
|
<p>计算两个字符串之间的汉明距离。汉明距离是指对应符号不同的位置数。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
HammingDistance(a, b string) (int, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
result1, _ := strutil.HammingDistance("de", "de")
|
||||||
|
result2, _ := strutil.HammingDistance("a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
```
|
```
|
||||||
+134
-134
@@ -903,52 +903,52 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
afterEncode := convertor.ToStdBase64(nil)
|
afterEncode := convertor.ToStdBase64(nil)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
afterEncode = convertor.ToStdBase64("")
|
afterEncode = convertor.ToStdBase64("")
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToStdBase64(stringVal)
|
afterEncode = convertor.ToStdBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
afterEncode = convertor.ToStdBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToStdBase64(intVal)
|
afterEncode = convertor.ToStdBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToStdBase64(mapVal)
|
afterEncode = convertor.ToStdBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToStdBase64(floatVal)
|
afterEncode = convertor.ToStdBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToStdBase64(boolVal)
|
afterEncode = convertor.ToStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToStdBase64(errVal)
|
afterEncode = convertor.ToStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
// MTIzLjQ1Ng==
|
// MTIzLjQ1Ng==
|
||||||
// dHJ1ZQ==
|
// dHJ1ZQ==
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -975,49 +975,49 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
afterEncode := convertor.ToUrlBase64(nil)
|
afterEncode := convertor.ToUrlBase64(nil)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToUrlBase64(stringVal)
|
afterEncode = convertor.ToUrlBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
afterEncode = convertor.ToUrlBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToUrlBase64(intVal)
|
afterEncode = convertor.ToUrlBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToUrlBase64(mapVal)
|
afterEncode = convertor.ToUrlBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToUrlBase64(floatVal)
|
afterEncode = convertor.ToUrlBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToUrlBase64(boolVal)
|
afterEncode = convertor.ToUrlBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToUrlBase64(errVal)
|
afterEncode = convertor.ToUrlBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// aGVsbG8=
|
// aGVsbG8=
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ==
|
||||||
// MTIzLjQ1Ng==
|
// MTIzLjQ1Ng==
|
||||||
// dHJ1ZQ==
|
// dHJ1ZQ==
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1044,45 +1044,45 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToRawStdBase64(stringVal)
|
afterEncode = convertor.ToRawStdBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
afterEncode = convertor.ToRawStdBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToRawStdBase64(intVal)
|
afterEncode = convertor.ToRawStdBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToRawStdBase64(mapVal)
|
afterEncode = convertor.ToRawStdBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToRawStdBase64(floatVal)
|
afterEncode = convertor.ToRawStdBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToRawStdBase64(boolVal)
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToRawStdBase64(errVal)
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
// MTIzLjQ1Ng
|
// MTIzLjQ1Ng
|
||||||
// dHJ1ZQ
|
// dHJ1ZQ
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1108,44 +1108,44 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
stringVal := "hello"
|
stringVal := "hello"
|
||||||
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
afterEncode = convertor.ToRawUrlBase64(stringVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
byteSliceVal := []byte("hello")
|
byteSliceVal := []byte("hello")
|
||||||
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
afterEncode = convertor.ToRawUrlBase64(byteSliceVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
intVal := 123
|
intVal := 123
|
||||||
afterEncode = convertor.ToRawUrlBase64(intVal)
|
afterEncode = convertor.ToRawUrlBase64(intVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
mapVal := map[string]any{"a": "hi", "b": 2, "c": struct {
|
||||||
A string
|
A string
|
||||||
B int
|
B int
|
||||||
}{"hello", 3}}
|
}{"hello", 3}}
|
||||||
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
afterEncode = convertor.ToRawUrlBase64(mapVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
floatVal := 123.456
|
floatVal := 123.456
|
||||||
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
afterEncode = convertor.ToRawUrlBase64(floatVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
boolVal := true
|
boolVal := true
|
||||||
afterEncode = convertor.ToRawStdBase64(boolVal)
|
afterEncode = convertor.ToRawStdBase64(boolVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
errVal := errors.New("err")
|
errVal := errors.New("err")
|
||||||
afterEncode = convertor.ToRawStdBase64(errVal)
|
afterEncode = convertor.ToRawStdBase64(errVal)
|
||||||
fmt.Println(afterEncode)
|
fmt.Println(afterEncode)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// aGVsbG8
|
// aGVsbG8
|
||||||
// MTIz
|
// MTIz
|
||||||
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
// eyJhIjoiaGkiLCJiIjoyLCJjIjp7IkEiOiJoZWxsbyIsIkIiOjN9fQ
|
||||||
// MTIzLjQ1Ng
|
// MTIzLjQ1Ng
|
||||||
// dHJ1ZQ
|
// dHJ1ZQ
|
||||||
// ZXJy
|
// ZXJy
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -50,6 +50,8 @@ import (
|
|||||||
- [WriteStringToFile](#WriteStringToFile)
|
- [WriteStringToFile](#WriteStringToFile)
|
||||||
- [WriteBytesToFile](#WriteBytesToFile)
|
- [WriteBytesToFile](#WriteBytesToFile)
|
||||||
- [ReadFile](#ReadFile)
|
- [ReadFile](#ReadFile)
|
||||||
|
- [ChunkRead](#ChunkRead)
|
||||||
|
- [ParallelChunkRead](#ParallelChunkRead)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -961,3 +963,115 @@ func main() {
|
|||||||
// Disallow: /deny
|
// Disallow: /deny
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ChunkRead">ChunkRead</span>
|
||||||
|
|
||||||
|
<p>reads a block from the file at the specified offset and returns all lines within the block.</p>
|
||||||
|
|
||||||
|
<b>Signature :</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ChunkRead(file *os.File, offset int64, size int, bufPool *sync.Pool) ([]string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100
|
||||||
|
|
||||||
|
// test1.csv file content:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
filePath := "./testdata/test1.csv"
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 0, defaultChunkSizeMB*mb)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines, err := fileutil.ChunkRead(f, 0, 100, &bufPool)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(lines[0])
|
||||||
|
fmt.Println(lines[1])
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="ParallelChunkRead">ParallelChunkRead</span>
|
||||||
|
|
||||||
|
<p>Reads the file in parallel and send each chunk of lines to the specified channel.</p>
|
||||||
|
|
||||||
|
<b>Signature :</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// filePath: file path.
|
||||||
|
// chunkSizeMB: The size of the block (in MB, the default is 100MB when set to 0). Setting it too large will be detrimental. Adjust it as appropriate.
|
||||||
|
// maxGoroutine: The number of concurrent read chunks, the number of CPU cores used when set to 0.
|
||||||
|
// linesCh: The channel used to receive the returned results.
|
||||||
|
func ParallelChunkRead(filePath string, linesCh chan<- []string, chunkSizeMB, maxGoroutine int) error
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/fileutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100 // 默认值
|
||||||
|
|
||||||
|
numParsers := runtime.NumCPU()
|
||||||
|
|
||||||
|
linesCh := make(chan []string, numParsers)
|
||||||
|
|
||||||
|
// test1.csv file content:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
filePath := "./testdata/test1.csv"
|
||||||
|
|
||||||
|
go fileutil.ParallelChunkRead(filePath, linesCh, defaultChunkSizeMB, numParsers)
|
||||||
|
|
||||||
|
var totalLines int
|
||||||
|
for lines := range linesCh {
|
||||||
|
totalLines += len(lines)
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(totalLines)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -39,6 +39,7 @@ import (
|
|||||||
- [Nor](#Nor)
|
- [Nor](#Nor)
|
||||||
- [Xnor](#Xnor)
|
- [Xnor](#Xnor)
|
||||||
- [Nand](#Nand)
|
- [Nand](#Nand)
|
||||||
|
- [AcceptIf](#AcceptIf)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -638,4 +639,57 @@ func main() {
|
|||||||
// true
|
// true
|
||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="AcceptIf">AcceptIf</span>
|
||||||
|
|
||||||
|
<p>AcceptIf returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure.
|
||||||
|
A predicate function that takes an argument of type T and returns a bool.
|
||||||
|
An apply function that also takes an argument of type T and returns a modified value of the same type.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
adder := AcceptIf(
|
||||||
|
And(
|
||||||
|
func(x int) bool {
|
||||||
|
return x > 10
|
||||||
|
}, func(x int) bool {
|
||||||
|
return x%2 == 0
|
||||||
|
}),
|
||||||
|
func(x int) int {
|
||||||
|
return x + 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result, ok := adder(20)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
result, ok = adder(21)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 21
|
||||||
|
// true
|
||||||
|
// 0
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -34,6 +34,10 @@ import (
|
|||||||
- [RoundToFloat](#RoundToFloat)
|
- [RoundToFloat](#RoundToFloat)
|
||||||
- [RoundToString](#RoundToString)
|
- [RoundToString](#RoundToString)
|
||||||
- [TruncRound](#TruncRound)
|
- [TruncRound](#TruncRound)
|
||||||
|
- [CeilToFloat](#CeilToFloat)
|
||||||
|
- [CeilToString](#CeilToString)
|
||||||
|
- [FloorToFloat](#FloorToFloat)
|
||||||
|
- [FloorToString](#FloorToString)
|
||||||
- [Range](#Range)
|
- [Range](#Range)
|
||||||
- [RangeWithStep](#RangeWithStep)
|
- [RangeWithStep](#RangeWithStep)
|
||||||
- [AngleToRadian](#AngleToRadian)
|
- [AngleToRadian](#AngleToRadian)
|
||||||
@@ -47,6 +51,7 @@ import (
|
|||||||
- [Log](#Log)
|
- [Log](#Log)
|
||||||
- [Sum](#Sum)
|
- [Sum](#Sum)
|
||||||
- [Abs](#Abs)
|
- [Abs](#Abs)
|
||||||
|
- [Div](#Div)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -493,6 +498,150 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToFloat">CeilToFloat</span>
|
||||||
|
|
||||||
|
<p>Round float up n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToFloat[T constraints.Float | constraints.Integer](x T, n int) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="CeilToString">CeilToString</span>
|
||||||
|
|
||||||
|
<p>Round float up n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.CeilToString(3.14159, 1)
|
||||||
|
result2 := mathutil.CeilToString(3.14159, 2)
|
||||||
|
result3 := mathutil.CeilToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToFloat">FloorToFloat</span>
|
||||||
|
|
||||||
|
<p>Round float down n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToFloat(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToFloat(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="FloorToString">FloorToString</span>
|
||||||
|
|
||||||
|
<p>Round float down n decimal places.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.FloorToString(3.14159, 1)
|
||||||
|
result2 := mathutil.FloorToString(3.14159, 2)
|
||||||
|
result3 := mathutil.FloorToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Range">Range</span>
|
### <span id="Range">Range</span>
|
||||||
|
|
||||||
<p>Creates a slice of numbers from start with specified count, element step is 1.</p>
|
<p>Creates a slice of numbers from start with specified count, element step is 1.</p>
|
||||||
@@ -964,17 +1113,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
result1 := Abs(-1)
|
result1 := mathutil.Abs(-1)
|
||||||
result2 := Abs(-0.1)
|
result2 := mathutil.Abs(-0.1)
|
||||||
result3 := Abs(float32(0.2))
|
result3 := mathutil.Abs(float32(0.2))
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
fmt.Println(result3)
|
fmt.Println(result3)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
// 0.1
|
// 0.1
|
||||||
// 0.2
|
// 0.2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Div">Div</span>
|
||||||
|
|
||||||
|
<p>returns the result of x divided by y.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Div[T constraints.Float | constraints.Integer](x T, y T) float64
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/mathutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
result1 := mathutil.Div(9, 4)
|
||||||
|
result2 := mathutil.Div(1, 2)
|
||||||
|
result3 := mathutil.Div(0, 666)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
// Output:
|
||||||
|
// 2.25
|
||||||
|
// 0.5
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -27,6 +27,10 @@ import (
|
|||||||
- [RetryFunc](#RetryFunc)
|
- [RetryFunc](#RetryFunc)
|
||||||
- [RetryDuration](#RetryDuration)
|
- [RetryDuration](#RetryDuration)
|
||||||
- [RetryTimes](#RetryTimes)
|
- [RetryTimes](#RetryTimes)
|
||||||
|
- [BackoffStrategy](#BackoffStrategy)
|
||||||
|
- [RetryWithCustomBackoff](#RetryWithCustomBackoff)
|
||||||
|
- [RetryWithLinearBackoff](#RetryWithLinearBackoff)
|
||||||
|
- [RetryWithExponentialWithJitterBackoff](#RetryWithExponentialWithJitterBackoff)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -259,3 +263,202 @@ func main() {
|
|||||||
// 3
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="BackoffStrategy">BackoffStrategy</span>
|
||||||
|
|
||||||
|
<p>An interface that defines a method for calculating backoff intervals.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// BackoffStrategy is an interface that defines a method for calculating backoff intervals.
|
||||||
|
type BackoffStrategy interface {
|
||||||
|
// CalculateInterval returns the time.Duration after which the next retry attempt should be made.
|
||||||
|
CalculateInterval() time.Duration
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExampleCustomBackoffStrategy struct {
|
||||||
|
interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||||
|
return c.interval + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&ExampleCustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="RetryWithCustomBackoff">RetryWithCustomBackoff</span>
|
||||||
|
|
||||||
|
<p>Set abitary custom backoff strategy.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExampleCustomBackoffStrategy struct {
|
||||||
|
interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ExampleCustomBackoffStrategy) CalculateInterval() time.Duration {
|
||||||
|
return c.interval + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry,Retry(increaseNumber, retry.RetryWithCustomBackoff(&ExampleCustomBackoffStrategy{interval: time.Microsecond * 50}))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RetryWithLinearBackoff">RetryWithLinearBackoff</span>
|
||||||
|
|
||||||
|
<p>Set linear strategy backoff.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithLinearBackoff(interval time.Duration) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry.Retry(increaseNumber, retry.RetryWithLinearBackoff(time.Microsecond*50))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="RetryWithExponentialWithJitterBackoff">RetryWithExponentialWithJitterBackoff</span>
|
||||||
|
|
||||||
|
<p>Set exponential strategy backoff.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func RetryWithExponentialWithJitterBackoff(interval time.Duration, base uint64, maxJitter time.Duration) Option
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"github.com/duke-git/lancet/v2/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
number := 0
|
||||||
|
increaseNumber := func() error {
|
||||||
|
number++
|
||||||
|
if number == 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("error occurs")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := retry.Retry(increaseNumber, retry.RetryWithExponentialWithJitterBackoff(time.Microsecond*50, 2, time.Microsecond*25))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(number)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ import (
|
|||||||
- [ContainsAll](#ContainsAll)
|
- [ContainsAll](#ContainsAll)
|
||||||
- [ContainsAny](#ContainsAny)
|
- [ContainsAny](#ContainsAny)
|
||||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||||
|
- [SubInBetween](#SubInBetween)
|
||||||
|
- [HammingDistance](#HammingDistance)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -1496,4 +1498,36 @@ func main() {
|
|||||||
// abc
|
// abc
|
||||||
// bc
|
// bc
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### <span id="HammingDistance">HammingDistance</span>
|
||||||
|
|
||||||
|
<p>HammingDistance calculates the Hamming distance between two strings. The Hamming distance is the number of positions at which the corresponding symbols are different.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
HammingDistance(a, b string) (int, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
result1, _ := strutil.HammingDistance("de", "de")
|
||||||
|
result2, _ := strutil.HammingDistance("a", "d")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 0
|
||||||
|
// 1
|
||||||
|
}
|
||||||
```
|
```
|
||||||
@@ -30,7 +30,7 @@ We are excited that you are interested in contributing to lancet. Before submitt
|
|||||||
|
|
||||||
- Before submitting a PR, please execute the unit test command: `go test -v ./...` to ensure that all unit test tasks should pass.
|
- Before submitting a PR, please execute the unit test command: `go test -v ./...` to ensure that all unit test tasks should pass.
|
||||||
|
|
||||||
- Make sure PRs are created to `v2` branch instead of `master` branch.
|
- Make sure PRs are created to `rc` branch instead of other branch.
|
||||||
|
|
||||||
- If your PR fixes a bug, please provide a description about the related bug.
|
- If your PR fixes a bug, please provide a description about the related bug.
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Lancet 的成长离不开大家的支持,如果你愿意为 Lancet 贡献代
|
|||||||
|
|
||||||
- 提交 PR 前请执行单元测试命令:go test -v ./...,确保所有单元测试任务通过。
|
- 提交 PR 前请执行单元测试命令:go test -v ./...,确保所有单元测试任务通过。
|
||||||
|
|
||||||
- 确保 PR 是提交到 `v2` 分支,而不是 `main` 分支。
|
- 确保 PR 是提交到 `rc` 分支,而不是其他分支。
|
||||||
|
|
||||||
- 如果是修复 bug,请在 PR 中给出描述信息。
|
- 如果是修复 bug,请在 PR 中给出描述信息。
|
||||||
|
|
||||||
|
|||||||
+30
-22
@@ -16,7 +16,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -869,12 +868,13 @@ func isCsvSupportedType(v interface{}) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChunkRead 从文件的指定偏移读取块并返回块内所有行
|
// ChunkRead reads a block from the file at the specified offset and returns all lines within the block
|
||||||
func ChunkRead(f *os.File, offset int64, size int, bufPool *sync.Pool) []string {
|
// Play: todo
|
||||||
|
func ChunkRead(file *os.File, offset int64, size int, bufPool *sync.Pool) ([]string, error) {
|
||||||
buf := bufPool.Get().([]byte)[:size] // 从Pool获取缓冲区并调整大小
|
buf := bufPool.Get().([]byte)[:size] // 从Pool获取缓冲区并调整大小
|
||||||
n, err := f.ReadAt(buf, offset) // 从指定偏移读取数据到缓冲区
|
n, err := file.ReadAt(buf, offset) // 从指定偏移读取数据到缓冲区
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Fatal(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
buf = buf[:n] // 调整切片以匹配实际读取的字节数
|
buf = buf[:n] // 调整切片以匹配实际读取的字节数
|
||||||
|
|
||||||
@@ -893,58 +893,64 @@ func ChunkRead(f *os.File, offset int64, size int, bufPool *sync.Pool) []string
|
|||||||
lines = append(lines, line)
|
lines = append(lines, line)
|
||||||
}
|
}
|
||||||
bufPool.Put(buf) // 读取完成后,将缓冲区放回Pool
|
bufPool.Put(buf) // 读取完成后,将缓冲区放回Pool
|
||||||
return lines
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 并行读取文件并将每个块的行发送到指定通道
|
// ParallelChunkRead reads the file in parallel and send each chunk of lines to the specified channel.
|
||||||
// filePath 文件路径
|
// filePath 文件路径
|
||||||
// ChunkSizeMB 分块的大小(单位MB,设置为0时使用默认100MB),设置过大反而不利,视情调整
|
// chunkSizeMB 分块的大小(单位MB,设置为0时使用默认100MB),设置过大反而不利,视情调整
|
||||||
// MaxGoroutine 并发读取分块的数量,设置为0时使用CPU核心数
|
// maxGoroutine 并发读取分块的数量,设置为0时使用CPU核心数
|
||||||
// linesCh用于接收返回结果的通道。
|
// linesCh用于接收返回结果的通道。
|
||||||
func ParallelChunkRead(filePath string, linesCh chan<- []string, ChunkSizeMB, MaxGoroutine int) {
|
// Play: todo
|
||||||
if ChunkSizeMB == 0 {
|
func ParallelChunkRead(filePath string, linesCh chan<- []string, chunkSizeMB, maxGoroutine int) error {
|
||||||
ChunkSizeMB = 100
|
if chunkSizeMB == 0 {
|
||||||
|
chunkSizeMB = 100
|
||||||
}
|
}
|
||||||
ChunkSize := ChunkSizeMB * 1024 * 1024
|
chunkSize := chunkSizeMB * 1024 * 1024
|
||||||
// 内存复用
|
// 内存复用
|
||||||
bufPool := sync.Pool{
|
bufPool := sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return make([]byte, 0, ChunkSize)
|
return make([]byte, 0, chunkSize)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if MaxGoroutine == 0 {
|
if maxGoroutine == 0 {
|
||||||
MaxGoroutine = runtime.NumCPU() // 设置为0时使用CPU核心数
|
maxGoroutine = runtime.NumCPU() // 设置为0时使用CPU核心数
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open(filePath)
|
f, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to open file: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
info, err := f.Stat()
|
info, err := f.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to get file info: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
chunkOffsetCh := make(chan int64, MaxGoroutine)
|
chunkOffsetCh := make(chan int64, maxGoroutine)
|
||||||
|
|
||||||
// 分配工作
|
// 分配工作
|
||||||
go func() {
|
go func() {
|
||||||
for i := int64(0); i < info.Size(); i += int64(ChunkSize) {
|
for i := int64(0); i < info.Size(); i += int64(chunkSize) {
|
||||||
chunkOffsetCh <- i
|
chunkOffsetCh <- i
|
||||||
}
|
}
|
||||||
close(chunkOffsetCh)
|
close(chunkOffsetCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 启动工作协程
|
// 启动工作协程
|
||||||
for i := 0; i < MaxGoroutine; i++ {
|
for i := 0; i < maxGoroutine; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
for chunkOffset := range chunkOffsetCh {
|
for chunkOffset := range chunkOffsetCh {
|
||||||
linesCh <- ChunkRead(f, chunkOffset, ChunkSize, &bufPool)
|
chunk, err := ChunkRead(f, chunkOffset, chunkSize, &bufPool)
|
||||||
|
if err == nil {
|
||||||
|
linesCh <- chunk
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
@@ -953,4 +959,6 @@ func ParallelChunkRead(filePath string, linesCh chan<- []string, ChunkSizeMB, Ma
|
|||||||
// 等待所有解析完成后关闭行通道
|
// 等待所有解析完成后关闭行通道
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(linesCh)
|
close(linesCh)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleIsExist() {
|
func ExampleIsExist() {
|
||||||
@@ -421,8 +423,69 @@ func ExampleReadFile() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(dat))
|
fmt.Println(string(dat))
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// User-agent: *
|
// User-agent: *
|
||||||
// Disallow: /deny
|
// Disallow: /deny
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleChunkRead() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100
|
||||||
|
|
||||||
|
filePath := "./testdata/test1.csv"
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 0, defaultChunkSizeMB*mb)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines, err := ChunkRead(f, 0, 100, &bufPool)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(lines[0])
|
||||||
|
fmt.Println(lines[1])
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleParallelChunkRead() {
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100 // 默认值
|
||||||
|
|
||||||
|
numParsers := runtime.NumCPU()
|
||||||
|
|
||||||
|
linesCh := make(chan []string, numParsers)
|
||||||
|
filePath := "./testdata/test1.csv"
|
||||||
|
|
||||||
|
go ParallelChunkRead(filePath, linesCh, defaultChunkSizeMB, numParsers)
|
||||||
|
|
||||||
|
var totalLines int
|
||||||
|
for lines := range linesCh {
|
||||||
|
totalLines += len(lines)
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(totalLines)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Lili,22,female
|
||||||
|
// Jim,21,male
|
||||||
|
// 2
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
@@ -566,3 +568,54 @@ func TestCopyDir(t *testing.T) {
|
|||||||
|
|
||||||
os.RemoveAll(dest)
|
os.RemoveAll(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParallelChunkRead(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestParallelChunkRead")
|
||||||
|
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100 // 默认值
|
||||||
|
|
||||||
|
numParsers := runtime.NumCPU()
|
||||||
|
|
||||||
|
linesCh := make(chan []string, numParsers)
|
||||||
|
filePath := "./testdata/test1.csv" // 替换为你的文件路径
|
||||||
|
|
||||||
|
go ParallelChunkRead(filePath, linesCh, defaultChunkSizeMB, numParsers)
|
||||||
|
|
||||||
|
var totalLines int
|
||||||
|
for lines := range linesCh {
|
||||||
|
totalLines += len(lines)
|
||||||
|
|
||||||
|
assert.Equal("Lili,22,female", lines[0])
|
||||||
|
assert.Equal("Jim,21,male", lines[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(2, totalLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChunkRead(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestChunkRead")
|
||||||
|
|
||||||
|
const mb = 1024 * 1024
|
||||||
|
const defaultChunkSizeMB = 100 // 默认值
|
||||||
|
|
||||||
|
filePath := "./testdata/test1.csv" // 替换为你的文件路径
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 0, defaultChunkSizeMB*mb)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines, err := ChunkRead(f, 0, 100, &bufPool)
|
||||||
|
|
||||||
|
assert.Equal("Lili,22,female", lines[0])
|
||||||
|
assert.Equal("Jim,21,male", lines[1])
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Vendored
-3
@@ -1,5 +1,2 @@
|
|||||||
Lili,22,female
|
Lili,22,female
|
||||||
Jim,21,male
|
Jim,21,male
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
@@ -136,6 +136,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AcceptIf returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure.
|
||||||
|
// A predicate function that takes an argument of type T and returns a bool.
|
||||||
|
// An apply function that also takes an argument of type T and returns a modified value of the same type.
|
||||||
|
func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool) {
|
||||||
|
if predicate == nil {
|
||||||
|
panic("programming error: predicate must be not nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if apply == nil {
|
||||||
|
panic("programming error: apply must be not nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(t T) (T, bool) {
|
||||||
|
if !predicate(t) {
|
||||||
|
var defaultValue T
|
||||||
|
return defaultValue, false
|
||||||
|
}
|
||||||
|
return apply(t), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||||
fv := reflect.ValueOf(fn)
|
fv := reflect.ValueOf(fn)
|
||||||
params := make([]reflect.Value, len(args))
|
params := make([]reflect.Value, len(args))
|
||||||
|
|||||||
@@ -145,3 +145,32 @@ func ExamplePipeline() {
|
|||||||
// Output:
|
// Output:
|
||||||
// 36
|
// 36
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleAcceptIf() {
|
||||||
|
|
||||||
|
adder := AcceptIf(
|
||||||
|
And(
|
||||||
|
func(x int) bool {
|
||||||
|
return x > 10
|
||||||
|
}, func(x int) bool {
|
||||||
|
return x%2 == 0
|
||||||
|
}),
|
||||||
|
func(x int) int {
|
||||||
|
return x + 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result, ok := adder(20)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
result, ok = adder(21)
|
||||||
|
fmt.Println(result)
|
||||||
|
fmt.Println(ok)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 21
|
||||||
|
// true
|
||||||
|
// 0
|
||||||
|
// false
|
||||||
|
}
|
||||||
|
|||||||
@@ -162,3 +162,63 @@ func TestPipeline(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(36, f(2))
|
assert.Equal(36, f(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAcceptIf(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "AcceptIf")
|
||||||
|
|
||||||
|
adder := AcceptIf(
|
||||||
|
And(
|
||||||
|
func(x int) bool {
|
||||||
|
return x > 10
|
||||||
|
}, func(x int) bool {
|
||||||
|
return x%2 == 0
|
||||||
|
}),
|
||||||
|
func(x int) int {
|
||||||
|
return x + 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result, ok := adder(20)
|
||||||
|
assert.Equal(21, result)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
result, ok = adder(21)
|
||||||
|
assert.Equal(0, result)
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAcceptIfPanicMissingPredicate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAcceptIfPanicMissingPredicate")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
v := recover()
|
||||||
|
assert.Equal("programming error: predicate must be not nil", v)
|
||||||
|
}()
|
||||||
|
|
||||||
|
AcceptIf(
|
||||||
|
nil,
|
||||||
|
func(x int) int {
|
||||||
|
return x
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAcceptIfPanicMissingApply(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestAcceptIfPanicMissingApply")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
v := recover()
|
||||||
|
assert.Equal("programming error: apply must be not nil", v)
|
||||||
|
}()
|
||||||
|
|
||||||
|
AcceptIf(
|
||||||
|
func(i int) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+47
-3
@@ -66,7 +66,7 @@ func Percent(val, total float64, n int) float64 {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoundToString round up to n decimal places.
|
// RoundToString round off to n decimal places.
|
||||||
// Play: https://go.dev/play/p/kZwpBRAcllO
|
// Play: https://go.dev/play/p/kZwpBRAcllO
|
||||||
func RoundToString[T constraints.Float | constraints.Integer](x T, n int) string {
|
func RoundToString[T constraints.Float | constraints.Integer](x T, n int) string {
|
||||||
tmp := math.Pow(10.0, float64(n))
|
tmp := math.Pow(10.0, float64(n))
|
||||||
@@ -76,7 +76,7 @@ func RoundToString[T constraints.Float | constraints.Integer](x T, n int) string
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoundToFloat round up to n decimal places.
|
// RoundToFloat round off to n decimal places.
|
||||||
// Play: https://go.dev/play/p/ghyb528JRJL
|
// Play: https://go.dev/play/p/ghyb528JRJL
|
||||||
func RoundToFloat[T constraints.Float | constraints.Integer](x T, n int) float64 {
|
func RoundToFloat[T constraints.Float | constraints.Integer](x T, n int) float64 {
|
||||||
tmp := math.Pow(10.0, float64(n))
|
tmp := math.Pow(10.0, float64(n))
|
||||||
@@ -100,6 +100,44 @@ func TruncRound[T constraints.Float | constraints.Integer](x T, n int) T {
|
|||||||
return T(result)
|
return T(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FloorToFloat round down to n decimal places.
|
||||||
|
// Play: todo
|
||||||
|
func FloorToFloat[T constraints.Float | constraints.Integer](x T, n int) float64 {
|
||||||
|
tmp := math.Pow(10.0, float64(n))
|
||||||
|
x *= T(tmp)
|
||||||
|
r := math.Floor(float64(x))
|
||||||
|
return r / tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloorToString round down to n decimal places.
|
||||||
|
// Play: todo
|
||||||
|
func FloorToString[T constraints.Float | constraints.Integer](x T, n int) string {
|
||||||
|
tmp := math.Pow(10.0, float64(n))
|
||||||
|
x *= T(tmp)
|
||||||
|
r := math.Floor(float64(x))
|
||||||
|
result := strconv.FormatFloat(r/tmp, 'f', n, 64)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeilToFloat round up to n decimal places.
|
||||||
|
// Play: todo
|
||||||
|
func CeilToFloat[T constraints.Float | constraints.Integer](x T, n int) float64 {
|
||||||
|
tmp := math.Pow(10.0, float64(n))
|
||||||
|
x *= T(tmp)
|
||||||
|
r := math.Ceil(float64(x))
|
||||||
|
return r / tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// CeilToString round up to n decimal places.
|
||||||
|
// Play: todo
|
||||||
|
func CeilToString[T constraints.Float | constraints.Integer](x T, n int) string {
|
||||||
|
tmp := math.Pow(10.0, float64(n))
|
||||||
|
x *= T(tmp)
|
||||||
|
r := math.Ceil(float64(x))
|
||||||
|
result := strconv.FormatFloat(r/tmp, 'f', n, 64)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// Max return max value of numbers.
|
// Max return max value of numbers.
|
||||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||||
@@ -253,7 +291,7 @@ func PointDistance(x1, y1, x2, y2 float64) float64 {
|
|||||||
return math.Sqrt(c)
|
return math.Sqrt(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPrimes checks if number is prime number.
|
// IsPrime checks if number is prime number.
|
||||||
// Play: https://go.dev/play/p/Rdd8UTHZJ7u
|
// Play: https://go.dev/play/p/Rdd8UTHZJ7u
|
||||||
func IsPrime(n int) bool {
|
func IsPrime(n int) bool {
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
@@ -351,3 +389,9 @@ func Abs[T constraints.Integer | constraints.Float](x T) T {
|
|||||||
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Div returns the result of x divided by y.
|
||||||
|
// Play: todo
|
||||||
|
func Div[T constraints.Float | constraints.Integer](x T, y T) float64 {
|
||||||
|
return float64(x) / float64(y)
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,6 +110,66 @@ func ExampleTruncRound() {
|
|||||||
// 0.125
|
// 0.125
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleCeilToFloat() {
|
||||||
|
result1 := CeilToFloat(3.14159, 1)
|
||||||
|
result2 := CeilToFloat(3.14159, 2)
|
||||||
|
result3 := CeilToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCeilToString() {
|
||||||
|
result1 := CeilToString(3.14159, 1)
|
||||||
|
result2 := CeilToString(3.14159, 2)
|
||||||
|
result3 := CeilToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.2
|
||||||
|
// 3.15
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFloorToFloat() {
|
||||||
|
result1 := FloorToFloat(3.14159, 1)
|
||||||
|
result2 := FloorToFloat(3.14159, 2)
|
||||||
|
result3 := FloorToFloat(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleFloorToString() {
|
||||||
|
result1 := FloorToString(3.14159, 1)
|
||||||
|
result2 := FloorToString(3.14159, 2)
|
||||||
|
result3 := FloorToString(5, 4)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3.1
|
||||||
|
// 3.14
|
||||||
|
// 5.0000
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleAverage() {
|
func ExampleAverage() {
|
||||||
result1 := Average(1, 2)
|
result1 := Average(1, 2)
|
||||||
result2 := RoundToFloat(Average(1.2, 1.4), 1)
|
result2 := RoundToFloat(Average(1.2, 1.4), 1)
|
||||||
@@ -404,3 +464,17 @@ func ExampleAbs() {
|
|||||||
// 0.1
|
// 0.1
|
||||||
// 0.2
|
// 0.2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleDiv() {
|
||||||
|
result1 := Div(9, 4)
|
||||||
|
result2 := Div(1, 2)
|
||||||
|
result3 := Div(0, 666)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
// Output:
|
||||||
|
// 2.25
|
||||||
|
// 0.5
|
||||||
|
// 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ func TestRoundToString(t *testing.T) {
|
|||||||
assert.Equal("0.12", RoundToString(0.124, 2))
|
assert.Equal("0.12", RoundToString(0.124, 2))
|
||||||
assert.Equal("0.13", RoundToString(0.125, 2))
|
assert.Equal("0.13", RoundToString(0.125, 2))
|
||||||
assert.Equal("0.125", RoundToString(0.125, 3))
|
assert.Equal("0.125", RoundToString(0.125, 3))
|
||||||
//assert.Equal("54.321", RoundToString(54.321, 3))
|
assert.Equal("54.321", RoundToString(54.321, 3))
|
||||||
//assert.Equal("17.000", RoundToString(17, 3))
|
assert.Equal("17.000", RoundToString(17, 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTruncRound(t *testing.T) {
|
func TestTruncRound(t *testing.T) {
|
||||||
@@ -93,6 +93,51 @@ func TestTruncRound(t *testing.T) {
|
|||||||
assert.Equal(33.33, TruncRound(33.33333, 2))
|
assert.Equal(33.33, TruncRound(33.33333, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFloorToFloat(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFloorToFloat")
|
||||||
|
|
||||||
|
assert.Equal(3.14, FloorToFloat(3.14159, 2))
|
||||||
|
assert.Equal(3.141, FloorToFloat(3.14159, 3))
|
||||||
|
assert.Equal(5.0, FloorToFloat(5, 4))
|
||||||
|
assert.Equal(2.0, FloorToFloat(9/4, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloorToString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestFloorToString")
|
||||||
|
|
||||||
|
assert.Equal("3.14", FloorToString(3.14159, 2))
|
||||||
|
assert.Equal("3.141", FloorToString(3.14159, 3))
|
||||||
|
assert.Equal("5.0000", FloorToString(5, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCeilToFloat(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestCeilToFloat")
|
||||||
|
|
||||||
|
assert.Equal(3.15, CeilToFloat(3.14159, 2))
|
||||||
|
assert.Equal(3.142, CeilToFloat(3.14159, 3))
|
||||||
|
assert.Equal(5.0, CeilToFloat(5, 4))
|
||||||
|
assert.Equal(2.25, CeilToFloat(float32(9)/float32(4), 2))
|
||||||
|
assert.Equal(0.15, CeilToFloat(float64(1)/float64(7), 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCeilToString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestCeilToFloat")
|
||||||
|
|
||||||
|
assert.Equal("3.15", CeilToString(3.14159, 2))
|
||||||
|
assert.Equal("3.142", CeilToString(3.14159, 3))
|
||||||
|
assert.Equal("5.0000", CeilToString(5, 4))
|
||||||
|
assert.Equal("2.25", CeilToString(float32(9)/float32(4), 2))
|
||||||
|
assert.Equal("0.15", CeilToString(float64(1)/float64(7), 2))
|
||||||
|
}
|
||||||
|
|
||||||
func TestAverage(t *testing.T) {
|
func TestAverage(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -352,4 +397,19 @@ func TestAbs(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(int64(1), Abs(int64(-1)))
|
assert.Equal(int64(1), Abs(int64(-1)))
|
||||||
assert.Equal(float32(1), Abs(float32(-1)))
|
assert.Equal(float32(1), Abs(float32(-1)))
|
||||||
|
assert.Equal(math.Inf(1), Abs(math.Inf(-1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiv(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestDiv")
|
||||||
|
|
||||||
|
assert.Equal(float64(2), Div(4, 2))
|
||||||
|
assert.Equal(2.5, Div(5, 2))
|
||||||
|
assert.Equal(0.5, Div(1, 2))
|
||||||
|
assert.Equal(0.5, Div(1, 2))
|
||||||
|
assert.Equal(math.Inf(1), Div(8, 0))
|
||||||
|
assert.Equal(math.Inf(-1), Div(-8, 0))
|
||||||
|
assert.Equal(true, math.IsNaN(Div(0, 0)))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -45,7 +45,7 @@ func RetryTimes(n uint) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RetryWithCustomBackoff set abitary custom backoff strategy
|
// RetryWithCustomBackoff set abitary custom backoff strategy
|
||||||
// todo: Add playground link
|
// Play: todo
|
||||||
func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option {
|
func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option {
|
||||||
if backoffStrategy == nil {
|
if backoffStrategy == nil {
|
||||||
panic("programming error: backoffStrategy must be not nil")
|
panic("programming error: backoffStrategy must be not nil")
|
||||||
@@ -57,7 +57,7 @@ func RetryWithCustomBackoff(backoffStrategy BackoffStrategy) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RetryWithLinearBackoff set linear strategy backoff
|
// RetryWithLinearBackoff set linear strategy backoff
|
||||||
// todo: Add playground link
|
// Play: todo
|
||||||
func RetryWithLinearBackoff(interval time.Duration) Option {
|
func RetryWithLinearBackoff(interval time.Duration) Option {
|
||||||
if interval <= 0 {
|
if interval <= 0 {
|
||||||
panic("programming error: retry interval should not be lower or equal to 0")
|
panic("programming error: retry interval should not be lower or equal to 0")
|
||||||
@@ -71,7 +71,7 @@ func RetryWithLinearBackoff(interval time.Duration) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RetryWithExponentialWithJitterBackoff set exponential strategy backoff
|
// RetryWithExponentialWithJitterBackoff set exponential strategy backoff
|
||||||
// todo: Add playground link
|
// Play: todo
|
||||||
func RetryWithExponentialWithJitterBackoff(interval time.Duration, base uint64, maxJitter time.Duration) Option {
|
func RetryWithExponentialWithJitterBackoff(interval time.Duration, base uint64, maxJitter time.Duration) Option {
|
||||||
if interval <= 0 {
|
if interval <= 0 {
|
||||||
panic("programming error: retry interval should not be lower or equal to 0")
|
panic("programming error: retry interval should not be lower or equal to 0")
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@ func AppendIfAbsent[T comparable](slice []T, item T) []T {
|
|||||||
// SetToDefaultIf sets elements to their default value if they match the given predicate.
|
// SetToDefaultIf sets elements to their default value if they match the given predicate.
|
||||||
// It retains the positions of the elements in the slice.
|
// It retains the positions of the elements in the slice.
|
||||||
// It returns slice of T and the count of modified slice items
|
// It returns slice of T and the count of modified slice items
|
||||||
|
// Play: todo
|
||||||
func SetToDefaultIf[T any](slice []T, predicate func(T) bool) ([]T, int) {
|
func SetToDefaultIf[T any](slice []T, predicate func(T) bool) ([]T, int) {
|
||||||
var count int
|
var count int
|
||||||
for i := 0; i < len(slice); i++ {
|
for i := 0; i < len(slice); i++ {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package strutil
|
package strutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
@@ -594,3 +595,25 @@ func SubInBetween(str string, start string, end string) string {
|
|||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HammingDistance calculates the Hamming distance between two strings.
|
||||||
|
// The Hamming distance is the number of positions at which the corresponding symbols are different.
|
||||||
|
// This func returns an error if the input strings are of unequal lengths.
|
||||||
|
// Play: todo
|
||||||
|
func HammingDistance(a, b string) (int, error) {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return -1, errors.New("a length and b length are unequal")
|
||||||
|
}
|
||||||
|
|
||||||
|
ar := []rune(a)
|
||||||
|
br := []rune(b)
|
||||||
|
|
||||||
|
var distance int
|
||||||
|
for i, codepoint := range ar {
|
||||||
|
if codepoint != br[i] {
|
||||||
|
distance++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -667,3 +667,16 @@ func ExampleSubInBetween() {
|
|||||||
// abc
|
// abc
|
||||||
// bc
|
// bc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleHammingDistance() {
|
||||||
|
|
||||||
|
result, _ := HammingDistance("abc", "def")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
result, _ = HammingDistance("name", "namf")
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 3
|
||||||
|
// 1
|
||||||
|
}
|
||||||
|
|||||||
@@ -581,3 +581,26 @@ func TestSubInBetween(t *testing.T) {
|
|||||||
assert.Equal("", SubInBetween(str, "a", ""))
|
assert.Equal("", SubInBetween(str, "a", ""))
|
||||||
assert.Equal("", SubInBetween(str, "a", "f"))
|
assert.Equal("", SubInBetween(str, "a", "f"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHammingDistance(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "HammingDistance")
|
||||||
|
|
||||||
|
hd := func(a, b string) int {
|
||||||
|
c, _ := HammingDistance(a, b)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(0, hd(" ", " "))
|
||||||
|
assert.Equal(1, hd(" ", "c"))
|
||||||
|
assert.Equal(1, hd("a", "d"))
|
||||||
|
assert.Equal(1, hd("a", " "))
|
||||||
|
assert.Equal(1, hd("a", "f"))
|
||||||
|
|
||||||
|
assert.Equal(0, hd("", ""))
|
||||||
|
assert.Equal(-1, hd("abc", "ab"))
|
||||||
|
assert.Equal(3, hd("abc", "def"))
|
||||||
|
assert.Equal(-1, hd("kitten", "sitting"))
|
||||||
|
assert.Equal(1, hd("ö", "ü"))
|
||||||
|
assert.Equal(0, hd("日本語", "日本語"))
|
||||||
|
assert.Equal(3, hd("日本語", "語日本"))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user