mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-23 13:52:26 +08:00
Compare commits
68 Commits
v2.2.0
...
17ff84fa1f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17ff84fa1f | ||
|
|
bf50baa07d | ||
|
|
7d56da8108 | ||
|
|
16c2df711b | ||
|
|
015f8c3f5c | ||
|
|
ba25701d89 | ||
|
|
a0cb4bb266 | ||
|
|
d6ba7497f9 | ||
|
|
7da931e0a0 | ||
|
|
8f49078eb3 | ||
|
|
3050d93703 | ||
|
|
efcfbfb6a1 | ||
|
|
844b7a2c3b | ||
|
|
c8a536eafc | ||
|
|
0fd268face | ||
|
|
8ced7e887f | ||
|
|
957568ed5c | ||
|
|
fffabd0ffa | ||
|
|
e839af3ef9 | ||
|
|
1650e70d04 | ||
|
|
23382b2b76 | ||
|
|
daa3aa3da2 | ||
|
|
be355a23f3 | ||
|
|
95af83b0cb | ||
|
|
1efdbc0973 | ||
|
|
9b829aa695 | ||
|
|
bfa9091c09 | ||
|
|
c11d63c2e2 | ||
|
|
83832daeb1 | ||
|
|
7311f84772 | ||
|
|
a63d78111e | ||
|
|
e2fc2f1bc9 | ||
|
|
23a0135947 | ||
|
|
013b6457bb | ||
|
|
e08a62b0ba | ||
|
|
850800a233 | ||
|
|
a6a8fd88bc | ||
|
|
2f6ee84443 | ||
|
|
b1c6614549 | ||
|
|
a8761eefb0 | ||
|
|
cbf8cfdffa | ||
|
|
286a187942 | ||
|
|
b787e99528 | ||
|
|
e54c9b2850 | ||
|
|
8944109c4c | ||
|
|
10e3732f32 | ||
|
|
a415597c6b | ||
|
|
69b32fd043 | ||
|
|
75ed359084 | ||
|
|
2c71b6375c | ||
|
|
2894bec80c | ||
|
|
09ec5b97a6 | ||
|
|
46ecb117a5 | ||
|
|
388171e739 | ||
|
|
6fbaf2b005 | ||
|
|
53a91cad71 | ||
|
|
a51a182fb2 | ||
|
|
64982f0c89 | ||
|
|
f38f69ce17 | ||
|
|
a33ea3d013 | ||
|
|
e35462fb14 | ||
|
|
af106a4a8e | ||
|
|
ec7232ec40 | ||
|
|
67c1b54b5a | ||
|
|
e149ae2f72 | ||
|
|
b1fcfce188 | ||
|
|
259dbce85e | ||
|
|
78aa679670 |
76
README.md
76
README.md
@@ -4,7 +4,7 @@
|
||||
<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://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -25,7 +25,7 @@ English | [简体中文](./README_zh-CN.md)
|
||||
|
||||
- 👏 Comprehensive, efficient and reusable.
|
||||
- 💪 500+ go util functions, support string, slice, datetime, net, crypt...
|
||||
- 💅 Only depend on the go standard library.
|
||||
- 💅 Only depends on two kinds of libraries: go standard library and golang.org/x.
|
||||
- 🌍 Unit test for every exported function.
|
||||
|
||||
## Installation
|
||||
@@ -38,7 +38,7 @@ English | [简体中文](./README_zh-CN.md)
|
||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||
```
|
||||
|
||||
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.8. </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.0. </b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet // below go1.18, install latest version of v1.x.x
|
||||
@@ -281,6 +281,14 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/oZujoB5Sgg5)]
|
||||
- **<big>ToInterface</big>** : converts reflect value to its interface type.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#ToInterface)]
|
||||
[[play](https://go.dev/play/p/syqw0-WG7Xd)]
|
||||
- **<big>Utf8ToGbk</big>** : converts utf8 encoding data to GBK encoding data
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#Utf8ToGbk)]
|
||||
[[play](https://go.dev/play/p/9FlIaFLArIL)]
|
||||
- **<big>GbkToUtf8</big>** : converts GBK encoding data to utf8 encoding data.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor.md#GbkToUtf8)]
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
|
||||
|
||||
### 6. Cryptor package is for data encryption and decryption.
|
||||
|
||||
@@ -405,6 +413,7 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||
- **<big>AddYear</big>** : add or sub year to the time.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#AddYear)]
|
||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||
- **<big>BeginOfMinute</big>** : return the date time at the begin of minute of specific date.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BeginOfMinute)]
|
||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||
@@ -488,6 +497,17 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
- **<big>IsLeapYear</big>** : check if param `year` is leap year or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#IsLeapYear)]
|
||||
[[play](https://go.dev/play/p/xS1eS2ejGew)]
|
||||
- **<big>BetweenSeconds</big>** : returns the number of seconds between two times.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BetweenSeconds)]
|
||||
[[play](https://go.dev/play/p/n3YDRyfyXJu)]
|
||||
- **<big>DayOfYear</big>** : returns which day of the year the parameter date `t` is.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#DayOfYear)]
|
||||
[[play](https://go.dev/play/p/0hjqhTwFNlH)]
|
||||
- **<big>IsWeekend</big>** : checks if passed time is weekend or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#IsWeekend)]
|
||||
[[play](https://go.dev/play/p/cupRM5aZOIY)]
|
||||
|
||||
|
||||
### 8. Datastructure package constains some common data structure. eg. list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
@@ -568,9 +588,11 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ReadFileByLine</big>** : read file line by line, return string slice of file content.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadFileByLine)]
|
||||
[[play](https://go.dev/play/p/svJP_7ZrBrD)]
|
||||
- **<big>Zip</big>** : create zip file.
|
||||
- **<big>Zip</big>** : create a zip file of fpath, fpath could be a file or a directory.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#Zip)]
|
||||
[[play](https://go.dev/play/p/j-3sWBp8ik_P)]
|
||||
- **<big>ZipAppendEntry</big>** : append a single file or directory by fpath to an existing zip file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ZipAppendEntry)]
|
||||
- **<big>UnZip</big>** : unzip the zip file and save it to dest path.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#UnZip)]
|
||||
[[play](https://go.dev/play/p/g0w34kS7B8m)]
|
||||
@@ -592,6 +614,16 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ReadCsvFile</big>** : read file content into slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#ReadCsvFile)]
|
||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
||||
- **<big>WriteCsvFile</big>** : write content to target csv file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteCsvFile)]
|
||||
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||
- **<big>WriteBytesToFile</big>** : write bytes to target file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteBytesToFile)]
|
||||
[[play](https://go.dev/play/p/s7QlDxMj3P8)]
|
||||
- **<big>WriteStringToFile</big>** : write string to target file.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#WriteStringToFile)]
|
||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||
|
||||
|
||||
### 10. Formatter contains some functions for data formatting.
|
||||
|
||||
@@ -765,7 +797,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>Percent</big>** : calculate the percentage of value to total.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Percent)]
|
||||
[[play](https://go.dev/play/p/QQM9B13coSP)]
|
||||
[[play](https://go.dev/play/p/s0NdFCtwuyd)]
|
||||
- **<big>RoundToFloat</big>** : round up to n decimal places for float64.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RoundToFloat)]
|
||||
[[play](https://go.dev/play/p/ghyb528JRJL)]
|
||||
@@ -795,8 +827,23 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
|
||||
- **<big>GCD</big>** : return greatest common divisor (GCD) of integers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#GCD)]
|
||||
[[play](https://go.dev/play/p/CiEceLSoAKB)]
|
||||
- **<big>LCM</big>** : return Least Common Multiple (LCM) of integers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#LCM)]
|
||||
[[play](https://go.dev/play/p/EjcZxfY7G_g)]
|
||||
- **<big>Cos</big>** : return the cosine of the radian argument.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Cos)]
|
||||
[[play](https://go.dev/play/p/Sm89LoIfvFq)]
|
||||
- **<big>Sin</big>** : return the sine of the radian argument.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sin)]
|
||||
[[play](https://go.dev/play/p/TWMQlMywDsP)]
|
||||
- **<big>Log</big>** : returns the logarithm of base n.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Log)]
|
||||
[[play](https://go.dev/play/p/_d4bi8oyhat)]
|
||||
- **<big>Sum</big>** : return sum of passed numbers.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Sum)]
|
||||
[[play](https://go.dev/play/p/1To2ImAMJA7)]
|
||||
|
||||
|
||||
### 14. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
@@ -903,6 +950,10 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>UUIdV4</big>** : generate a random UUID of version 4 according to RFC 4122.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
- **<big>RandUniqueIntSlice</big>** : generate a slice of random int of length n that do not repeat.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
|
||||
|
||||
### 16. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
@@ -1205,6 +1256,7 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
[[play](https://go.dev/play/p/9xEf0-6C1e3)]
|
||||
- **<big>FindLast</big>** : returns the last element of this stream and true, or zero value and false if the stream is empty.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/WZD2rDAW-2h)]
|
||||
- **<big>Max</big>** : returns the maximum element of this stream according to the provided less function. less fuction: a > b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream.md#Max)]
|
||||
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
|
||||
@@ -1285,6 +1337,12 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>Capitalize</big>** : converts the first character of source string to upper case and the remaining to lower case.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Capitalize)]
|
||||
[[play](https://go.dev/play/p/2OAjgbmAqHZ)]
|
||||
- **<big>ContainsAll</big>** : return true if target string contains all the substrings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ContainsAll)]
|
||||
[[play](https://go.dev/play/p/KECtK2Os4zq)]
|
||||
- **<big>ContainsAny</big>** : return true if target string contains any one of the substrings.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ContainsAny)]
|
||||
[[play](https://go.dev/play/p/dZGSSMB3LXE)]
|
||||
- **<big>IsString</big>** : checks if the parameter value data type is string or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#IsString)]
|
||||
[[play](https://go.dev/play/p/IOgq7oF9ERm)]
|
||||
@@ -1359,10 +1417,18 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/qZo4lV2fomB)]
|
||||
- **<big>ReplaceWithMap</big>** : returns a copy of `str`, which is replaced by a map in unordered way, case-sensitively.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#ReplaceWithMap)]
|
||||
[[play](https://go.dev/play/p/h3t7CNj2Vvu)]
|
||||
- **<big>Trim</big>** : strips whitespace (or other characters) from the beginning and end of a string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#Trim)]
|
||||
[[play](https://go.dev/play/p/Y0ilP0NRV3j)]
|
||||
- **<big>SplitAndTrim</big>** : splits string `str` by a string `delimiter` to a slice, and calls Trim to every element of slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#SplitAndTrim)]
|
||||
[[play](https://go.dev/play/p/ZNL6o4SkYQ7)]
|
||||
- **<big>HideString</big>** : Hide some chars in source string with param `replaceChar`.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#HideString)]
|
||||
[[play](https://go.dev/play/p/pzbaIVCTreZ)]
|
||||
- **<big>RemoveWhiteSpace</big>** : remove whitespace characters from a string.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveWhiteSpace)]
|
||||
|
||||
### 21. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<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://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
## 特性
|
||||
|
||||
- 👏 全面、高效、可复用
|
||||
- 👏 全面、高效、可复用。
|
||||
- 💪 500+常用 go 工具函数,支持 string、slice、datetime、net、crypt...
|
||||
- 💅 只依赖 go 标准库
|
||||
- 🌍 所有导出函数单元测试覆盖率 100%
|
||||
- 💅 只依赖 go 标准库和 golang.org/x。
|
||||
- 🌍 所有导出函数单元测试覆盖率 100%。
|
||||
|
||||
## 安装
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||
```
|
||||
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.7。</b>
|
||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.4.0。</b>
|
||||
|
||||
```go
|
||||
go get github.com/duke-git/lancet// 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||
@@ -280,6 +280,14 @@ import "github.com/duke-git/lancet/v2/convertor"
|
||||
[[play](https://go.dev/play/p/oZujoB5Sgg5)]
|
||||
- **<big>ToInterface</big>** : 将反射值转换成对应的 interface 类型。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#ToInterface)]
|
||||
[[play](https://go.dev/play/p/syqw0-WG7Xd)]
|
||||
- **<big>Utf8ToGbk</big>** : utf8 编码转 GBK 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#Utf8ToGbk)]
|
||||
[[play](https://go.dev/play/p/9FlIaFLArIL)]
|
||||
- **<big>GbkToUtf8</big>** : GBK 编码转 utf8 编码。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#GbkToUtf8)]
|
||||
[[play](https://go.dev/play/p/OphmHCN_9u8)]
|
||||
|
||||
|
||||
### 6. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
@@ -404,6 +412,7 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
[[play](https://go.dev/play/p/nT1heB1KUUK)]
|
||||
- **<big>AddYear</big>** : 将日期加/减分年数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#AddYear)]
|
||||
[[play](https://go.dev/play/p/MqW2ujnBx10)]
|
||||
- **<big>BeginOfMinute</big>** : 返回指定时间的分钟开始时间。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BeginOfMinute)]
|
||||
[[play](https://go.dev/play/p/ieOLVJ9CiFT)]
|
||||
@@ -479,14 +488,27 @@ import "github.com/duke-git/lancet/v2/datetime"
|
||||
- **<big>ToFormat</big>** : 返回格式'yyyy-mm-dd hh:mm:ss'的日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormat)]
|
||||
[[play](https://go.dev/play/p/VkW08ZOaXPZ)]
|
||||
- **<big>ToFormatForTpl</big>** : 返回tpl格式指定的日期字符串。
|
||||
- **<big>ToFormatForTpl</big>** : 返回 tpl 格式指定的日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToFormatForTpl)]
|
||||
[[play](https://go.dev/play/p/nyXxXcQJ8L5)]
|
||||
- **<big>ToIso8601</big>** : 返回iso8601日期字符串。
|
||||
- **<big>ToIso8601</big>** : 返回 iso8601 日期字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#ToIso8601)]
|
||||
[[play](https://go.dev/play/p/mkhOHQkdeA2)]
|
||||
- **<big>IsLeapYear</big>** :验证是否是闰年。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#IsLeapYear)]
|
||||
[[play](https://go.dev/play/p/xS1eS2ejGew)]
|
||||
- **<big>IsLeapYear</big>** : check if param `year` is leap year or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#IsLeapYear)]
|
||||
[[play](https://go.dev/play/p/xS1eS2ejGew)]
|
||||
- **<big>BetweenSeconds</big>** : 返回两个时间的间隔秒数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#BetweenSeconds)]
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime.md#BetweenSeconds)]
|
||||
- **<big>DayOfYear</big>** : 返回参数日期是一年中的第几天。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#DayOfYear)]
|
||||
[[play](https://go.dev/play/p/0hjqhTwFNlH)]
|
||||
- **<big>IsWeekend</big>** : 判断日期是否是周末。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/datetime_zh-CN.md#IsWeekend)]
|
||||
[[play](https://go.dev/play/p/cupRM5aZOIY)]
|
||||
|
||||
### 8. datastructure 包含一些普通的数据结构实现。例如:list, linklist, stack, queue, set, tree, graph.
|
||||
|
||||
@@ -570,6 +592,8 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>Zip</big>** : zip 压缩文件, 参数可以是文件或目录。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#Zip)]
|
||||
[[play](https://go.dev/play/p/j-3sWBp8ik_P)]
|
||||
- **<big>ZipAppendEntry</big>** : 通过将单个文件或目录追加到现有的 zip 文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ZipAppendEntry)]
|
||||
- **<big>UnZip</big>** : zip 解压缩文件并保存在目录中。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#UnZip)]
|
||||
[[play](https://go.dev/play/p/g0w34kS7B8m)]
|
||||
@@ -591,6 +615,15 @@ import "github.com/duke-git/lancet/v2/fileutil"
|
||||
- **<big>ReadCsvFile</big>** : 读取 csv 文件内容到切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#ReadCsvFile)]
|
||||
[[play](https://go.dev/play/p/OExTkhGEd3_u)]
|
||||
- **<big>WriteCsvFile</big>** : 向 csv 文件写入内容。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteCsvFile)]
|
||||
[[play](https://go.dev/play/p/dAXm58Q5U1o)]
|
||||
- **<big>WriteBytesToFile</big>** : 将 bytes 写入文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteBytesToFile)]
|
||||
[[play](https://go.dev/play/p/s7QlDxMj3P8)]
|
||||
- **<big>WriteStringToFile</big>** : 将字符串写入文件。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#WriteStringToFile)]
|
||||
[[play](https://go.dev/play/p/GhLS6d8lH_g)]
|
||||
|
||||
### 10. formatter 格式化器包含一些数据格式化处理方法。
|
||||
|
||||
@@ -764,7 +797,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||
- **<big>Percent</big>** : 计算百分比,可以指定保留 n 位小数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Percent)]
|
||||
[[play](https://go.dev/play/p/QQM9B13coSP)]
|
||||
[[play](https://go.dev/play/p/s0NdFCtwuyd)]
|
||||
- **<big>RoundToFloat</big>** : 四舍五入,保留 n 位小数,返回 float64。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToFloat)]
|
||||
[[play](https://go.dev/play/p/ghyb528JRJL)]
|
||||
@@ -794,8 +827,23 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
||||
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
|
||||
- **<big>GCD</big>** : 求最大公约数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#GCD)]
|
||||
[[play](https://go.dev/play/p/CiEceLSoAKB)]
|
||||
- **<big>LCM</big>** : 求最小公倍数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#LCM)]
|
||||
[[play](https://go.dev/play/p/EjcZxfY7G_g)]
|
||||
- **<big>Cos</big>** : 计算弧度的余弦值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Cos)]
|
||||
[[play](https://go.dev/play/p/Sm89LoIfvFq)]
|
||||
- **<big>Sin</big>** : 计算弧度的正弦值。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sin)]
|
||||
[[play](https://go.dev/play/p/TWMQlMywDsP)]
|
||||
- **<big>Log</big>** : 计算以 base 为底 n 的对数。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Log)]
|
||||
[[play](https://go.dev/play/p/_d4bi8oyhat)]
|
||||
- **<big>Sum</big>** : 求传入参数之和。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Sum)]
|
||||
[[play](https://go.dev/play/p/1To2ImAMJA7)]
|
||||
|
||||
|
||||
### 14. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
|
||||
@@ -902,6 +950,10 @@ import "github.com/duke-git/lancet/v2/random"
|
||||
- **<big>UUIdV4</big>** : 生成 UUID v4 字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#UUIdV4)]
|
||||
[[play](https://go.dev/play/p/_Z9SFmr28ft)]
|
||||
- **<big>RandUniqueIntSlice</big>** : 生成一个不重复的长度为n的随机int切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandUniqueIntSlice)]
|
||||
[[play](https://go.dev/play/p/uBkRSOz73Ec)]
|
||||
|
||||
|
||||
### 16. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
|
||||
@@ -1140,7 +1192,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||
|
||||
### 18. Stream流,该包仅验证简单的stream实现,功能有限。
|
||||
### 18. Stream 流,该包仅验证简单的 stream 实现,功能有限。
|
||||
|
||||
```go
|
||||
import "github.com/duke-git/lancet/v2/stream"
|
||||
@@ -1199,11 +1251,12 @@ import "github.com/duke-git/lancet/v2/stream"
|
||||
- **<big>Reduce</big>** : 使用关联累加函数对 stream 的元素执行 reduce 操作,并 reduce 操作结果(如果有)。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Reduce)]
|
||||
[[play](https://go.dev/play/p/6uzZjq_DJLU)]
|
||||
- **<big>FindFirst</big>** : 返回此 stream的第一个元素,如果 stream 为空,则返回零值和 false。
|
||||
- **<big>FindFirst</big>** : 返回此 stream 的第一个元素,如果 stream 为空,则返回零值和 false。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FindFirst)]
|
||||
[[play](https://go.dev/play/p/9xEf0-6C1e3)]
|
||||
- **<big>FindLast</big>** : 返回此 stream的最后一个元素,如果 stream 为空,则返回零值和 false。
|
||||
- **<big>FindLast</big>** : 返回此 stream 的最后一个元素,如果 stream 为空,则返回零值和 false。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#FindLast)]
|
||||
[[play](https://go.dev/play/p/WZD2rDAW-2h)]
|
||||
- **<big>Max</big>** : 根据提供的 less 函数返回 stream 的最大元素。less 函数: a > b
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/stream_zh-CN.md#Max)]
|
||||
[[play](https://go.dev/play/p/fm-1KOPtGzn)]
|
||||
@@ -1287,6 +1340,12 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
- **<big>Capitalize</big>** : 将字符串的第一个字符转换为大写。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Capitalize)]
|
||||
[[play](https://go.dev/play/p/2OAjgbmAqHZ)]
|
||||
- **<big>ContainsAll</big>** : 判断字符串是否包括全部给定的子字符串切片。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ContainsAll)]
|
||||
[[play](https://go.dev/play/p/KECtK2Os4zq)]
|
||||
- **<big>ContainsAny</big>** : 判断字符串是否包括给定的子字符串切片中任意一个子字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ContainsAny)]
|
||||
[[play](https://go.dev/play/p/dZGSSMB3LXE)]
|
||||
- **<big>IsString</big>** : 判断传入参数的数据类型是否为字符串。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#IsString)]
|
||||
[[play](https://go.dev/play/p/IOgq7oF9ERm)]
|
||||
@@ -1361,10 +1420,18 @@ import "github.com/duke-git/lancet/v2/strutil"
|
||||
[[play](https://go.dev/play/p/qZo4lV2fomB)]
|
||||
- **<big>ReplaceWithMap</big>** : 返回 string 的副本,以无序的方式被 map 替换,区分大小写。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#ReplaceWithMap)]
|
||||
[[play](https://go.dev/play/p/h3t7CNj2Vvu)]
|
||||
- **<big>Trim</big>** : 从字符串的开头和结尾去除空格(或其他字符)。 可选参数 characterMask 指定额外的剥离字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Trim)]
|
||||
- **<big>SplitAndTrim</big>** : 将字符串str按字符串delimiter拆分为一个切片,并对该数组的每个元素调用Trim。忽略Trim后为空的元素。
|
||||
[[play](https://go.dev/play/p/Y0ilP0NRV3j)]
|
||||
- **<big>SplitAndTrim</big>** : 将字符串 str 按字符串 delimiter 拆分为一个切片,并对该数组的每个元素调用 Trim。忽略 Trim 后为空的元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#SplitAndTrim)]
|
||||
[[play](https://go.dev/play/p/ZNL6o4SkYQ7)]
|
||||
- **<big>HideString</big>** : 隐藏源字符串中的一些字符。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#HideString)]
|
||||
[[play](https://go.dev/play/p/pzbaIVCTreZ)]
|
||||
- **<big>RemoveWhiteSpace</big>** : 删除字符串中的空格。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveWhiteSpace)]
|
||||
|
||||
### 21. system 包含 os, runtime, shell command 的相关函数。
|
||||
|
||||
|
||||
@@ -11,12 +11,15 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// ToBool convert string to boolean.
|
||||
@@ -349,7 +352,7 @@ func CopyProperties[T, U any](dst T, src U) error {
|
||||
}
|
||||
|
||||
// ToInterface converts reflect value to its interface type.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/syqw0-WG7Xd
|
||||
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
|
||||
if v.IsValid() && v.CanInterface() {
|
||||
return v.Interface(), true
|
||||
@@ -375,3 +378,19 @@ func ToInterface(v reflect.Value) (value interface{}, ok bool) {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Utf8ToGbk convert utf8 encoding data to GBK encoding data.
|
||||
// Play: https://go.dev/play/p/9FlIaFLArIL
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error) {
|
||||
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
|
||||
b, err := io.ReadAll(r)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// GbkToUtf8 convert GBK encoding data to utf8 encoding data.
|
||||
// Play: https://go.dev/play/p/OphmHCN_9u8
|
||||
func GbkToUtf8(bs []byte) ([]byte, error) {
|
||||
r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
|
||||
b, err := io.ReadAll(r)
|
||||
return b, err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func ExampleToBool() {
|
||||
@@ -364,3 +367,27 @@ func ExampleToInterface() {
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleUtf8ToGbk() {
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, _ := Utf8ToGbk(utf8Data)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(validator.IsGBK(gbkData))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGbkToUtf8() {
|
||||
gbkData, _ := Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, _ := GbkToUtf8(gbkData)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(string(utf8Data))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
"github.com/duke-git/lancet/v2/slice"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func TestToChar(t *testing.T) {
|
||||
@@ -396,3 +398,25 @@ func TestToInterface(t *testing.T) {
|
||||
assert.EqualValues(nil, nilVal)
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestUtf8ToGbk(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUtf8ToGbk")
|
||||
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, err := Utf8ToGbk(utf8Data)
|
||||
|
||||
assert.Equal(true, utf8.Valid(utf8Data))
|
||||
assert.Equal(true, validator.IsGBK(gbkData))
|
||||
assert.IsNil(err)
|
||||
}
|
||||
|
||||
func TestGbkToUtf8(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGbkToUtf8")
|
||||
|
||||
gbkData, err := Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, err := GbkToUtf8(gbkData)
|
||||
|
||||
assert.IsNil(err)
|
||||
assert.Equal(true, utf8.Valid(utf8Data))
|
||||
assert.Equal("hello", string(utf8Data))
|
||||
}
|
||||
|
||||
@@ -40,6 +40,14 @@ func Md5String(s string) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5String return the md5 string of byte slice.
|
||||
// Play: todo
|
||||
func Md5Byte(data []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(data)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5File return the md5 value of file.
|
||||
func Md5File(filename string) (string, error) {
|
||||
if fileInfo, err := os.Stat(filename); err != nil {
|
||||
|
||||
@@ -21,6 +21,12 @@ func TestMd5String(t *testing.T) {
|
||||
assert.Equal("5d41402abc4b2a76b9719d911017c592", Md5String("hello"))
|
||||
}
|
||||
|
||||
func TestMd5Byte(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMd5Byte")
|
||||
data := []byte{'a'}
|
||||
assert.Equal("0cc175b9c0f1b6a831c399e269772661", Md5Byte(data))
|
||||
}
|
||||
|
||||
func TestMd5File(t *testing.T) {
|
||||
fileMd5, err := Md5File("./basic.go")
|
||||
assert := internal.NewAssert(t, "TestMd5File")
|
||||
|
||||
@@ -366,21 +366,22 @@ func ExampleHmacSha512() {
|
||||
}
|
||||
|
||||
func ExampleMd5String() {
|
||||
str := "hello"
|
||||
|
||||
md5Str := Md5String(str)
|
||||
|
||||
md5Str := Md5String("hello")
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 5d41402abc4b2a76b9719d911017c592
|
||||
}
|
||||
|
||||
func ExampleMd5Byte() {
|
||||
md5Str := Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
func ExampleSha1() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha1(str)
|
||||
|
||||
result := Sha1("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
@@ -388,10 +389,7 @@ func ExampleSha1() {
|
||||
}
|
||||
|
||||
func ExampleSha256() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha256(str)
|
||||
|
||||
result := Sha256("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
@@ -399,10 +397,7 @@ func ExampleSha256() {
|
||||
}
|
||||
|
||||
func ExampleSha512() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha512(str)
|
||||
|
||||
result := Sha512("hello")
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
// Package datastructure implements some data structure. hashmap structure.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
// Package datastructure implements some data structure. MaxHeap is a binary max heap.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. Link structure contains SinglyLink and DoublyLink.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
// Package datastructure contains some data structure. list is a linear table, implemented with slice.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||
// Package datastructure implements some data structure.
|
||||
package datastructure
|
||||
|
||||
// LinkNode is a linkedlist node, which have a Value and Pre points to previous node, Next points to a next node of the link.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure.
|
||||
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure.
|
||||
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure.
|
||||
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure.
|
||||
// Queue structure contains ArrayQueue, LinkedQueue, CircularQueue, and PriorityQueue.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. Set is a data container, like slice, but element of set is not duplicate.
|
||||
package datastructure
|
||||
|
||||
// Set is a data container, like slice, but element of set is not duplicate
|
||||
// Set is a data container, like slice, but element of set is not duplicate.
|
||||
type Set[T comparable] map[T]struct{}
|
||||
|
||||
// NewSet return a instance of set
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
|
||||
package datastructure
|
||||
|
||||
import "errors"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. Stack structure contains ArrayStack and LinkedStack.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package datastructure contains some data structure. BSTree is binary search tree.
|
||||
package datastructure
|
||||
|
||||
import (
|
||||
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
timeFormat = map[string]string{
|
||||
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
|
||||
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd hh": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd hh": "2006-01-02 15",
|
||||
"yyyy-mm-dd": "2006-01-02",
|
||||
"yyyy-mm": "2006-01",
|
||||
"mm-dd": "01-02",
|
||||
@@ -73,7 +73,7 @@ func AddDay(t time.Time, day int64) time.Time {
|
||||
}
|
||||
|
||||
// AddYear add or sub year to the time.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/MqW2ujnBx10
|
||||
func AddYear(t time.Time, year int64) time.Time {
|
||||
return t.Add(365 * 24 * time.Hour * time.Duration(year))
|
||||
}
|
||||
@@ -96,6 +96,18 @@ func GetNowDateTime() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// GetTodayStartTime return the start time of today, format: yyyy-mm-dd 00:00:00.
|
||||
// Play: todo
|
||||
func GetTodayStartTime() string {
|
||||
return time.Now().Format("2006-01-02") + " 00:00:00"
|
||||
}
|
||||
|
||||
// GetTodayEndTime return the end time of today, format: yyyy-mm-dd 23:59:59.
|
||||
// Play: todo
|
||||
func GetTodayEndTime() string {
|
||||
return time.Now().Format("2006-01-02") + " 23:59:59"
|
||||
}
|
||||
|
||||
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
|
||||
// Play: https://go.dev/play/p/QmL2oIaGE3q
|
||||
func GetZeroHourTimestamp() int64 {
|
||||
@@ -226,7 +238,30 @@ func EndOfYear(t time.Time) time.Time {
|
||||
}
|
||||
|
||||
// IsLeapYear check if param year is leap year or not.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/xS1eS2ejGew
|
||||
func IsLeapYear(year int) bool {
|
||||
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
|
||||
}
|
||||
|
||||
// BetweenSeconds returns the number of seconds between two times.
|
||||
// Play: https://go.dev/play/p/n3YDRyfyXJu
|
||||
func BetweenSeconds(t1 time.Time, t2 time.Time) int64 {
|
||||
index := t2.Unix() - t1.Unix()
|
||||
return index
|
||||
}
|
||||
|
||||
// DayOfYear returns which day of the year the parameter date `t` is.
|
||||
// Play: https://go.dev/play/p/0hjqhTwFNlH
|
||||
func DayOfYear(t time.Time) int {
|
||||
y, m, d := t.Date()
|
||||
firstDay := time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
|
||||
nowDate := time.Date(y, m, d, 0, 0, 0, 0, t.Location())
|
||||
|
||||
return int(nowDate.Sub(firstDay).Hours() / 24)
|
||||
}
|
||||
|
||||
// IsWeekend checks if passed time is weekend or not.
|
||||
// Play: https://go.dev/play/p/cupRM5aZOIY
|
||||
func IsWeekend(t time.Time) bool {
|
||||
return time.Saturday == t.Weekday() || time.Sunday == t.Weekday()
|
||||
}
|
||||
|
||||
@@ -131,15 +131,18 @@ func ExampleFormatTimeToStr() {
|
||||
result1 := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss")
|
||||
result2 := FormatTimeToStr(datetime, "yyyy-mm-dd")
|
||||
result3 := FormatTimeToStr(datetime, "dd-mm-yy hh:mm:ss")
|
||||
result4 := FormatTimeToStr(datetime, "yyyy-mm-dd hh")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 2021-01-02 16:04:08
|
||||
// 2021-01-02
|
||||
// 02-01-21 16:04:08
|
||||
// 2021-01-02 16
|
||||
}
|
||||
|
||||
func ExampleFormatStrToTime() {
|
||||
@@ -350,3 +353,58 @@ func ExampleIsLeapYear() {
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleBetweenSeconds() {
|
||||
today := time.Now()
|
||||
tomorrow := AddDay(today, 1)
|
||||
yesterday := AddDay(today, -1)
|
||||
|
||||
result1 := BetweenSeconds(today, tomorrow)
|
||||
result2 := BetweenSeconds(today, yesterday)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 86400
|
||||
// -86400
|
||||
}
|
||||
|
||||
func ExampleDayOfYear() {
|
||||
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||
result1 := DayOfYear(date1)
|
||||
|
||||
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||
result2 := DayOfYear(date2)
|
||||
|
||||
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||
result3 := DayOfYear(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 31
|
||||
// 1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleIsWeekend() {
|
||||
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||
|
||||
result1 := IsWeekend(date1)
|
||||
result2 := IsWeekend(date2)
|
||||
result3 := IsWeekend(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
@@ -20,6 +20,20 @@ func TestAddYear(t *testing.T) {
|
||||
assert.Equal(float64(-8760), diff2.Hours())
|
||||
}
|
||||
|
||||
func TestBetweenSeconds(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBetweenSeconds")
|
||||
|
||||
today := time.Now()
|
||||
tomorrow := AddDay(today, 1)
|
||||
yesterday := AddDay(today, -1)
|
||||
|
||||
result1 := BetweenSeconds(today, tomorrow)
|
||||
result2 := BetweenSeconds(today, yesterday)
|
||||
|
||||
assert.Equal(int64(86400), result1)
|
||||
assert.Equal(int64(-86400), result2)
|
||||
}
|
||||
|
||||
func TestAddDay(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAddDay")
|
||||
|
||||
@@ -77,6 +91,18 @@ func TestGetNowDateTime(t *testing.T) {
|
||||
assert.Equal(expected, GetNowDateTime())
|
||||
}
|
||||
|
||||
func TestGetTodayStartTime(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetTodayStartTime")
|
||||
expected := time.Now().Format("2006-01-02") + " 00:00:00"
|
||||
assert.Equal(expected, GetTodayStartTime())
|
||||
}
|
||||
|
||||
func TestGetTodayEndTime(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetTodayEndTime")
|
||||
expected := time.Now().Format("2006-01-02") + " 23:59:59"
|
||||
assert.Equal(expected, GetTodayEndTime())
|
||||
}
|
||||
|
||||
func TestFormatTimeToStr(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFormatTimeToStr")
|
||||
|
||||
@@ -84,12 +110,16 @@ func TestFormatTimeToStr(t *testing.T) {
|
||||
cases := []string{
|
||||
"yyyy-mm-dd hh:mm:ss", "yyyy-mm-dd",
|
||||
"dd-mm-yy hh:mm:ss", "yyyy/mm/dd hh:mm:ss",
|
||||
"hh:mm:ss", "yyyy/mm"}
|
||||
"hh:mm:ss", "yyyy/mm",
|
||||
"yyyy-mm-dd hh",
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"2021-01-02 16:04:08", "2021-01-02",
|
||||
"02-01-21 16:04:08", "2021/01/02 16:04:08",
|
||||
"16:04:08", "2021/01"}
|
||||
"16:04:08", "2021/01",
|
||||
"2021-01-02 16",
|
||||
}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual := FormatTimeToStr(datetime, cases[i])
|
||||
@@ -253,3 +283,34 @@ func TestIsLeapYear(t *testing.T) {
|
||||
assert.Equal(true, result1)
|
||||
assert.Equal(false, result2)
|
||||
}
|
||||
|
||||
func TestDayOfYear(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestDayOfYear")
|
||||
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||
result1 := DayOfYear(date1)
|
||||
assert.Equal(31, result1)
|
||||
|
||||
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||
result2 := DayOfYear(date2)
|
||||
assert.Equal(1, result2)
|
||||
|
||||
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||
result3 := DayOfYear(date3)
|
||||
assert.Equal(0, result3)
|
||||
}
|
||||
|
||||
func TestIsWeekend(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsWeekend")
|
||||
date := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||
result := IsWeekend(date)
|
||||
assert.Equal(true, result)
|
||||
|
||||
date1 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||
result1 := IsWeekend(date1)
|
||||
assert.Equal(true, result1)
|
||||
|
||||
date2 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||
result2 := IsWeekend(date2)
|
||||
assert.Equal(false, result2)
|
||||
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import (
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
- [Utf8ToGbk](#Utf8ToGbk)
|
||||
- [GbkToUtf8](#GbkToUtf8)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -795,15 +797,82 @@ import (
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||
|
||||
<p>Converts utf8 encoding data to GBK encoding data.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(validator.IsGBK(gbkData))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||
|
||||
<p>Converts GBK encoding data to utf8 encoding data.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(string(utf8Data))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
```
|
||||
@@ -41,6 +41,8 @@ import (
|
||||
- [DeepClone](#DeepClone)
|
||||
- [CopyProperties](#CopyProperties)
|
||||
- [ToInterface](#ToInterface)
|
||||
- [Utf8ToGbk](#Utf8ToGbk)
|
||||
- [GbkToUtf8](#GbkToUtf8)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -795,15 +797,82 @@ import (
|
||||
|
||||
func main() {
|
||||
val := reflect.ValueOf("abc")
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
iVal, ok := convertor.ToInterface(val)
|
||||
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
fmt.Printf("%T\n", iVal)
|
||||
fmt.Printf("%v\n", iVal)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
// Output:
|
||||
// string
|
||||
// abc
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Utf8ToGbk">Utf8ToGbk</span>
|
||||
|
||||
<p>utf8编码转GBK编码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Utf8ToGbk(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
"github.com/duke-git/lancet/v2/validator"
|
||||
)
|
||||
|
||||
func main() {
|
||||
utf8Data := []byte("hello")
|
||||
gbkData, _ := convertor.Utf8ToGbk(utf8Data)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(validator.IsGBK(gbkData))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GbkToUtf8">GbkToUtf8</span>
|
||||
|
||||
<p>GBK编码转utf8编码。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GbkToUtf8(bs []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/convertor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbkData, _ := convertor.Utf8ToGbk([]byte("hello"))
|
||||
utf8Data, _ := convertor.GbkToUtf8(gbkData)
|
||||
|
||||
fmt.Println(utf8.Valid(utf8Data))
|
||||
fmt.Println(string(utf8Data))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
- [HmacSha256](#HmacSha256)
|
||||
- [HmacSha512](#HmacSha512)
|
||||
- [Md5String](#Md5String)
|
||||
- [Md5Byte](#Md5Byte)
|
||||
- [Md5File](#Md5File)
|
||||
- [Sha1](#Sha1)
|
||||
- [Sha256](#Sha256)
|
||||
@@ -880,6 +881,35 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Md5Byte">Md5Byte</span>
|
||||
|
||||
<p>Return the md5 string of byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Md5Byte(data []byte) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Md5File">Md5File</span>
|
||||
|
||||
<p>Get the md5 value of file.</p>
|
||||
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
- [HmacSha256](#HmacSha256)
|
||||
- [HmacSha512](#HmacSha512)
|
||||
- [Md5String](#Md5String)
|
||||
- [Md5Byte](#Md5Byte)
|
||||
- [Md5File](#Md5File)
|
||||
- [Sha1](#Sha1)
|
||||
- [Sha256](#Sha256)
|
||||
@@ -879,6 +880,35 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Md5Byte">Md5Byte</span>
|
||||
|
||||
<p>获取byte slice的md5至。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Md5Byte(data []byte) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/cryptor"
|
||||
)
|
||||
|
||||
func main() {
|
||||
md5Str := cryptor.Md5Byte([]byte{'a'})
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 0cc175b9c0f1b6a831c399e269772661
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Md5File">Md5File</span>
|
||||
|
||||
<p>获取文件md5值。</p>
|
||||
|
||||
217
docs/datetime.md
217
docs/datetime.md
@@ -42,6 +42,8 @@ import (
|
||||
- [GetNowDate](#GetNowDate)
|
||||
- [GetNowTime](#GetNowTime)
|
||||
- [GetNowDateTime](#GetNowDateTime)
|
||||
- [GetTodayStartTime](#GetTodayStartTime)
|
||||
- [GetTodayEndTime](#GetTodayEndTime)
|
||||
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
@@ -55,6 +57,9 @@ import (
|
||||
- [ToFormatForTpl](#ToFormatForTpl)
|
||||
- [ToIso8601](#ToIso8601)
|
||||
- [IsLeapYear](#IsLeapYear)
|
||||
- [BetweenSeconds](#BetweenSeconds)
|
||||
- [DayOfYear](#DayOfYear)
|
||||
- [IsWeekend](#IsWeekend)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -224,18 +229,18 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
|
||||
after1Year := AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
after1Year := datetime.AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
|
||||
before1Year := AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
before1Year := datetime.AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
}
|
||||
```
|
||||
|
||||
@@ -640,14 +645,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentDate := datetime.GetNowDate()
|
||||
|
||||
fmt.Println(currentDate)
|
||||
|
||||
// Output:
|
||||
@@ -672,14 +674,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentTime := datetime.GetNowTime()
|
||||
|
||||
fmt.Println(currentTime) // 15:57:33
|
||||
|
||||
// Output:
|
||||
@@ -704,14 +703,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
current := datetime.GetNowDateTime()
|
||||
|
||||
fmt.Println(current)
|
||||
|
||||
// Output:
|
||||
@@ -719,6 +715,64 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetTodayStartTime">GetTodayStartTime</span>
|
||||
|
||||
<p>Return the start time of today, format: yyyy-mm-dd 00:00:00.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetTodayStartTime() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
startTime := datetime.GetTodayStartTime()
|
||||
fmt.Println(startTime)
|
||||
|
||||
// Output:
|
||||
// 2023-06-29 00:00:00
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetTodayEndTime">GetTodayEndTime</span>
|
||||
|
||||
<p>Return the end time of today, format: yyyy-mm-dd 23:59:59.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetTodayEndTime() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endTime := datetime.GetTodayEndTime()
|
||||
fmt.Println(endTime)
|
||||
|
||||
// Output:
|
||||
// 2023-06-29 23:59:59
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
||||
|
||||
<p>Return timestamp of zero hour (timestamp of 00:00).</p>
|
||||
@@ -736,14 +790,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
zeroTime := datetime.GetZeroHourTimestamp()
|
||||
|
||||
fmt.Println(zeroTime)
|
||||
|
||||
// Output:
|
||||
@@ -768,14 +819,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
nightTime := datetime.GetNightTimestamp()
|
||||
|
||||
fmt.Println(nightTime)
|
||||
|
||||
// Output:
|
||||
@@ -1136,3 +1184,124 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="BetweenSeconds">BetweenSeconds</span>
|
||||
|
||||
<p>Return the number of seconds between two times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func BetweenSeconds(t1 time.Time, t2 time.Time) int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
today := time.Now()
|
||||
tomorrow := datetime.AddDay(today, 1)
|
||||
yesterday := datetime.AddDay(today, -1)
|
||||
|
||||
result1 := datetime.BetweenSeconds(today, tomorrow)
|
||||
result2 := datetime.BetweenSeconds(today, yesterday)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 86400
|
||||
// -86400
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="DayOfYear">DayOfYear</span>
|
||||
|
||||
<p>Returns which day of the year the parameter date `t` is.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func DayOfYear(t time.Time) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||
result1 := datetime.DayOfYear(date1)
|
||||
|
||||
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||
result2 := datetime.DayOfYear(date2)
|
||||
|
||||
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||
result3 := datetime.DayOfYear(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 31
|
||||
// 1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsWeekend">IsWeekend</span>
|
||||
|
||||
<p>Checks if passed time is weekend or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsWeekend(t time.Time) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||
|
||||
result1 := datetime.IsWeekend(date1)
|
||||
result2 := datetime.IsWeekend(date2)
|
||||
result3 := datetime.IsWeekend(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -41,6 +41,8 @@ import (
|
||||
- [GetNowDate](#GetNowDate)
|
||||
- [GetNowTime](#GetNowTime)
|
||||
- [GetNowDateTime](#GetNowDateTime)
|
||||
- [GetTodayStartTime](#GetTodayStartTime)
|
||||
- [GetTodayEndTime](#GetTodayEndTime)
|
||||
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
@@ -54,6 +56,10 @@ import (
|
||||
- [ToFormatForTpl](#ToFormatForTpl)
|
||||
- [ToIso8601](#ToIso8601)
|
||||
- [IsLeapYear](#IsLeapYear)
|
||||
- [BetweenSeconds](#BetweenSeconds)
|
||||
- [DayOfYear](#DayOfYear)
|
||||
- [IsWeekend](#IsWeekend)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -223,18 +229,18 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
|
||||
after1Year := AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
after1Year := datetime.AddYear(now, 1)
|
||||
diff1 := after1Year.Sub(now)
|
||||
|
||||
before1Year := AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
before1Year := datetime.AddYear(now, -1)
|
||||
diff2 := before1Year.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
// Output:
|
||||
// 8760h0m0s
|
||||
// -8760h0m0s
|
||||
}
|
||||
```
|
||||
|
||||
@@ -639,14 +645,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentDate := datetime.GetNowDate()
|
||||
|
||||
fmt.Println(currentDate)
|
||||
|
||||
// Output:
|
||||
@@ -671,15 +674,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentTime := datetime.GetNowTime()
|
||||
|
||||
fmt.Println(currentTime) // 15:57:33
|
||||
fmt.Println(currentTime)
|
||||
|
||||
// Output:
|
||||
// 15:57:33
|
||||
@@ -703,14 +703,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
current := datetime.GetNowDateTime()
|
||||
|
||||
fmt.Println(current)
|
||||
|
||||
// Output:
|
||||
@@ -718,6 +715,64 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetTodayStartTime">GetTodayStartTime</span>
|
||||
|
||||
<p>返回当天开始时间, 格式: yyyy-mm-dd 00:00:00.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetTodayStartTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
startTime := datetime.GetTodayStartTime()
|
||||
fmt.Println(startTime)
|
||||
|
||||
// Output:
|
||||
// 2023-06-29 00:00:00
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetTodayEndTime">GetTodayEndTime</span>
|
||||
|
||||
<p>返回当天结束时间,格式: yyyy-mm-dd 23:59:59.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetTodayEndTime() string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endTime := datetime.GetTodayEndTime()
|
||||
fmt.Println(endTime)
|
||||
|
||||
// Output:
|
||||
// 2023-06-29 23:59:59
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
||||
|
||||
<p>获取零点时间戳(timestamp of 00:00)</p>
|
||||
@@ -735,14 +790,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
zeroTime := datetime.GetZeroHourTimestamp()
|
||||
|
||||
fmt.Println(zeroTime)
|
||||
|
||||
// Output:
|
||||
@@ -767,14 +819,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
nightTime := datetime.GetNightTimestamp()
|
||||
|
||||
fmt.Println(nightTime)
|
||||
|
||||
// Output:
|
||||
@@ -1103,7 +1152,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsLeapYear">IsLeapYear</span>
|
||||
|
||||
<p>验证是否是闰年。</p>
|
||||
@@ -1136,3 +1184,121 @@ func main() {
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BetweenSeconds">BetweenSeconds</span>
|
||||
|
||||
<p>返回两个时间的间隔秒数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BetweenSeconds(t1 time.Time, t2 time.Time) int64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
today := time.Now()
|
||||
tomorrow := datetime.AddDay(today, 1)
|
||||
yesterday := datetime.AddDay(today, -1)
|
||||
|
||||
result1 := datetime.BetweenSeconds(today, tomorrow)
|
||||
result2 := datetime.BetweenSeconds(today, yesterday)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 86400
|
||||
// -86400
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="DayOfYear">DayOfYear</span>
|
||||
|
||||
<p>返回参数日期是一年中的第几天。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DayOfYear(t time.Time) int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1 := time.Date(2023, 02, 01, 1, 1, 1, 0, time.Local)
|
||||
result1 := datetime.DayOfYear(date1)
|
||||
|
||||
date2 := time.Date(2023, 01, 02, 1, 1, 1, 0, time.Local)
|
||||
result2 := datetime.DayOfYear(date2)
|
||||
|
||||
date3 := time.Date(2023, 01, 01, 1, 1, 1, 0, time.Local)
|
||||
result3 := datetime.DayOfYear(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 31
|
||||
// 1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsWeekend">IsWeekend</span>
|
||||
|
||||
<p>判断日期是否是周末。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsWeekend(t time.Time) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
date1 := time.Date(2023, 06, 03, 0, 0, 0, 0, time.Local)
|
||||
date2 := time.Date(2023, 06, 04, 0, 0, 0, 0, time.Local)
|
||||
date3 := time.Date(2023, 06, 02, 0, 0, 0, 0, time.Local)
|
||||
|
||||
result1 := datetime.IsWeekend(date1)
|
||||
result2 := datetime.IsWeekend(date2)
|
||||
result3 := datetime.IsWeekend(date3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
179
docs/fileutil.md
179
docs/fileutil.md
@@ -37,12 +37,16 @@ import (
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [ZipAppendEntry](#ZipAppendEntry)
|
||||
- [UnZip](#UnZip)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
- [MTime](#MTime)
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteStringToFile](#WriteStringToFile)
|
||||
- [WriteBytesToFile](#WriteBytesToFile)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -473,6 +477,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||
|
||||
<p>Append a single file or directory by fpath to an existing zip file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ZipAppendEntry(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UnZip">UnZip</span>
|
||||
|
||||
<p>Unzip the file and save it to dest path.</p>
|
||||
@@ -660,3 +692,150 @@ func main() {
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteCsvFile">WriteCsvFile</span>
|
||||
|
||||
<p>Write content to target csv file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fpath := "./test.csv"
|
||||
fileutil.CreateFile(fpath)
|
||||
|
||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
data := [][]string{
|
||||
{"Lili", "22", "female"},
|
||||
{"Jim", "21", "male"},
|
||||
}
|
||||
err := fileutil.WriteCsvFile(fpath, data, false)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadCsvFile(fpath)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||
|
||||
<p>Writes bytes to target file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func WriteBytesToFile(filepath string, content []byte) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filepath := "./bytes.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteStringToFile">WriteStringToFile</span>
|
||||
|
||||
<p>Writes string to target file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func WriteStringToFile(filepath string, content string, append bool) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filepath := "./test.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = fileutil.WriteStringToFile(filepath, "hello", true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -37,12 +37,16 @@ import (
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [ZipAppendEntry](#ZipAppendEntry)
|
||||
- [UnZip](#UnZip)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
- [MTime](#MTime)
|
||||
- [Sha](#Sha)
|
||||
- [ReadCsvFile](#ReadCsvFile)
|
||||
- [WriteCsvFile](#WriteCsvFile)
|
||||
- [WriteStringToFile](#WriteStringToFile)
|
||||
- [WriteBytesToFile](#WriteBytesToFile)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -473,6 +477,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||
|
||||
<p>通过将单个文件或目录追加到现有的zip文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ZipAppendEntry(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UnZip">UnZip</span>
|
||||
|
||||
<p>zip解压缩文件并保存在目录中</p>
|
||||
@@ -660,3 +692,150 @@ func main() {
|
||||
// <nil>
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteCsvFile">WriteCsvFile</span>
|
||||
|
||||
<p>向csv文件写入内容。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fpath := "./test.csv"
|
||||
fileutil.CreateFile(fpath)
|
||||
|
||||
f, _ := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
data := [][]string{
|
||||
{"Lili", "22", "female"},
|
||||
{"Jim", "21", "male"},
|
||||
}
|
||||
err := fileutil.WriteCsvFile(fpath, data, false)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadCsvFile(fpath)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [[Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteBytesToFile">WriteBytesToFile</span>
|
||||
|
||||
<p>将bytes写入文件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func WriteBytesToFile(filepath string, content []byte) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filepath := "./bytes.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = fileutil.WriteBytesToFile(filepath, []byte("hello"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="WriteStringToFile">WriteStringToFile</span>
|
||||
|
||||
<p>将字符串写入文件。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func WriteStringToFile(filepath string, content string, append bool) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filepath := "./test.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = fileutil.WriteStringToFile(filepath, "hello", true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileutil.ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
282
docs/mathutil.md
282
docs/mathutil.md
@@ -42,6 +42,12 @@ import (
|
||||
- [IsPrime](#IsPrime)
|
||||
- [GCD](#GCD)
|
||||
- [LCM](#LCM)
|
||||
- [Cos](#Cos)
|
||||
- [Sin](#Sin)
|
||||
- [Log](#Log)
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -365,18 +371,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Percent(1, 2, 2)
|
||||
result2 := Percent(0.1, 0.3, 2)
|
||||
result3 := Percent(-30305, 408420, 2)
|
||||
result1 := mathutil.Percent(1, 2, 2)
|
||||
result2 := mathutil.Percent(0.1, 0.3, 2)
|
||||
result3 := mathutil.Percent(-30305, 408420, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 50
|
||||
// 33.33
|
||||
// -7.42
|
||||
// Output:
|
||||
// 50
|
||||
// 33.33
|
||||
// -7.42
|
||||
}
|
||||
```
|
||||
|
||||
@@ -602,7 +608,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="RadianToAngle">RadianToAngle</span>
|
||||
|
||||
<p>Converts radian value to angle value.</p>
|
||||
@@ -669,7 +674,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsPrime">IsPrime</span>
|
||||
|
||||
<p>Checks if number is prime number.</p>
|
||||
@@ -692,20 +696,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.IsPrime(-1)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -731,27 +735,26 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.GCD(1, 1)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="LCM">LCM</span>
|
||||
|
||||
<p>Return Least Common Multiple (LCM) of integers.</p>
|
||||
@@ -774,8 +777,199 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.LCM(1, 1)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Cos">Cos</span>
|
||||
|
||||
<p>Returns the cosine of the radian argument.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Cos(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Cos(0)
|
||||
result2 := mathutil.Cos(90)
|
||||
result3 := mathutil.Cos(180)
|
||||
result4 := mathutil.Cos(math.Pi)
|
||||
result5 := mathutil.Cos(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -0.447
|
||||
// -0.598
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Sin">Sin</span>
|
||||
|
||||
<p>Returns the sine of the radian argument.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sin(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sin(0)
|
||||
result2 := mathutil.Sin(90)
|
||||
result3 := mathutil.Sin(180)
|
||||
result4 := mathutil.Sin(math.Pi)
|
||||
result5 := mathutil.Sin(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0.894
|
||||
// -0.801
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Log">Log</span>
|
||||
|
||||
<p>Returns the logarithm of base n.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Log(n, base float64) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 2.32
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sum">Sum</span>
|
||||
|
||||
<p>Returns sum of passed numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sum(1, 2)
|
||||
result2 := mathutil.Sum(0.1, float64(1))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Abs">Abs</span>
|
||||
|
||||
<p>Returns the absolute value of x.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Abs[T constraints.Integer | constraints.Float](x T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Abs(-1)
|
||||
result2 := Abs(-0.1)
|
||||
result3 := Abs(float32(0.2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -783,7 +977,7 @@ func main() {
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
// 0.1
|
||||
// 0.2
|
||||
}
|
||||
```
|
||||
@@ -42,6 +42,11 @@ import (
|
||||
- [IsPrime](#IsPrime)
|
||||
- [GCD](#GCD)
|
||||
- [LCM](#LCM)
|
||||
- [Cos](#Cos)
|
||||
- [Sin](#Sin)
|
||||
- [Log](#Log)
|
||||
- [Sum](#Sum)
|
||||
- [Abs](#Abs)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -365,18 +370,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Percent(1, 2, 2)
|
||||
result2 := Percent(0.1, 0.3, 2)
|
||||
result3 := Percent(-30305, 408420, 2)
|
||||
result1 := mathutil.Percent(1, 2, 2)
|
||||
result2 := mathutil.Percent(0.1, 0.3, 2)
|
||||
result3 := mathutil.Percent(-30305, 408420, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 50
|
||||
// 33.33
|
||||
// -7.42
|
||||
// Output:
|
||||
// 50
|
||||
// 33.33
|
||||
// -7.42
|
||||
}
|
||||
```
|
||||
|
||||
@@ -668,8 +673,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsPrime">IsPrime</span>
|
||||
|
||||
<p>判断质数。</p>
|
||||
@@ -692,20 +695,20 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.IsPrime(-1)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
result2 := mathutil.IsPrime(0)
|
||||
result3 := mathutil.IsPrime(1)
|
||||
result4 := mathutil.IsPrime(2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -731,27 +734,26 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.GCD(1, 1)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
result2 := mathutil.GCD(1, -1)
|
||||
result3 := mathutil.GCD(-1, 1)
|
||||
result4 := mathutil.GCD(-1, -1)
|
||||
result5 := mathutil.GCD(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// -1
|
||||
// -1
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="LCM">LCM</span>
|
||||
|
||||
<p>计算最小公倍数。</p>
|
||||
@@ -774,8 +776,197 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.LCM(1, 1)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
result2 := mathutil.LCM(1, 2)
|
||||
result3 := mathutil.LCM(3, 6, 9)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Cos">Cos</span>
|
||||
|
||||
<p>计算弧度的余弦值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Cos(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Cos(0)
|
||||
result2 := mathutil.Cos(90)
|
||||
result3 := mathutil.Cos(180)
|
||||
result4 := mathutil.Cos(math.Pi)
|
||||
result5 := mathutil.Cos(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -0.447
|
||||
// -0.598
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sin">Sin</span>
|
||||
|
||||
<p>计算弧度的正弦值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sin(radian float64, precision ...int) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sin(0)
|
||||
result2 := mathutil.Sin(90)
|
||||
result3 := mathutil.Sin(180)
|
||||
result4 := mathutil.Sin(math.Pi)
|
||||
result5 := mathutil.Sin(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0.894
|
||||
// -0.801
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Log">Log</span>
|
||||
|
||||
<p>计算以base为底n的对数。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Log(n, base float64) float64
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Log(8, 2)
|
||||
result2 := mathutil.TruncRound(mathutil.Log(5, 2), 2)
|
||||
result3 := mathutil.TruncRound(mathutil.Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 2.32
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Sum">Sum</span>
|
||||
|
||||
<p>求传入参数之和。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := mathutil.Sum(1, 2)
|
||||
result2 := mathutil.Sum(0.1, float64(1))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.1
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Abs">Abs</span>
|
||||
|
||||
<p>求绝对值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Abs[T constraints.Integer | constraints.Float](x T) T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := Abs(-1)
|
||||
result2 := Abs(-0.1)
|
||||
result3 := Abs(float32(0.2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
@@ -783,7 +974,7 @@ func main() {
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 18
|
||||
// 0.1
|
||||
// 0.2
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -620,9 +620,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpGet">HttpGet</span>
|
||||
|
||||
<p>Send http get request.</p>
|
||||
<p>Send http get request. (Deprecated: use SendRequest for replacement)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -662,9 +662,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPost">HttpPost</span>
|
||||
|
||||
<p>Send http post request.</p>
|
||||
<p>Send http post request.(Deprecated: use SendRequest for replacement)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -692,16 +692,14 @@ import (
|
||||
func main() {
|
||||
url := "https://jsonplaceholder.typicode.com/todos"
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
todo := Todo{1, "TestAddToDo"}
|
||||
bodyParams, _ := json.Marshal(todo)
|
||||
|
||||
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
|
||||
postData := url.Values{}
|
||||
postData.Add("userId", "1")
|
||||
postData.Add("title", "TestToDo")
|
||||
|
||||
resp, err := netutil.HttpPost(apiUrl, header, nil, postData)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -711,9 +709,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPut">HttpPut</span>
|
||||
|
||||
<p>Send http put request.</p>
|
||||
<p>Send http put request. (Deprecated: use SendRequest for replacement)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -761,9 +759,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpDelete">HttpDelete</span>
|
||||
|
||||
<p>Send http delete request.</p>
|
||||
<p>Send http delete request. (Deprecated: use SendRequest for replacement)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -800,9 +798,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPatch">HttpPatch</span>
|
||||
|
||||
<p>Send http patch request.</p>
|
||||
<p>Send http patch request. (Deprecated: use SendRequest for replacement)</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
||||
@@ -622,9 +622,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpGet">HttpGet (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpGet">HttpGet</span>
|
||||
|
||||
<p>发送http get请求</p>
|
||||
<p>发送http get请求。(已废弃:使用SendRequest)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -664,9 +664,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPost">HttpPost (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPost">HttpPost</span>
|
||||
|
||||
<p>发送http post请求</p>
|
||||
<p>发送http post请求。(已废弃:使用SendRequest)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -694,16 +694,14 @@ import (
|
||||
func main() {
|
||||
url := "https://jsonplaceholder.typicode.com/todos"
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
todo := Todo{1, "TestAddToDo"}
|
||||
bodyParams, _ := json.Marshal(todo)
|
||||
|
||||
resp, err := netutil.HttpPost(url, header, nil, bodyParams)
|
||||
postData := url.Values{}
|
||||
postData.Add("userId", "1")
|
||||
postData.Add("title", "TestToDo")
|
||||
|
||||
resp, err := netutil.HttpPost(apiUrl, header, nil, postData)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -713,9 +711,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPut">HttpPut (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPut">HttpPut</span>
|
||||
|
||||
<p>发送http put请求</p>
|
||||
<p>发送http put请求。(已废弃:使用SendRequest)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -763,9 +761,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpDelete">HttpDelete (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpDelete">HttpDelete</span>
|
||||
|
||||
<p>发送http delete请求</p>
|
||||
<p>发送http delete请求。(已废弃:使用SendRequest)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -802,9 +800,9 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HttpPatch">HttpPatch (Deprecated: use SendRequest for replacement)</span>
|
||||
### <span id="HttpPatch">HttpPatch</span>
|
||||
|
||||
<p>发送http patch请求</p>
|
||||
<p>发送http patch请求。(已废弃:使用SendRequest)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -245,3 +246,30 @@ func main() {
|
||||
fmt.Println(uuid)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||
|
||||
<p>Generate a slice of random int of length n that do not repeat.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RandUniqueIntSlice(n, min, max int) []int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandUniqueIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
- [RandNumeral](#RandNumeral)
|
||||
- [RandNumeralOrLetter](#RandNumeralOrLetter)
|
||||
- [UUIdV4](#UUIdV4)
|
||||
- [RandUniqueIntSlice](#RandUniqueIntSlice)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -245,3 +246,29 @@ func main() {
|
||||
fmt.Println(uuid)
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RandUniqueIntSlice">RandUniqueIntSlice</span>
|
||||
|
||||
<p>生成一个不重复的长度为n的随机int切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RandUniqueIntSlice(n, min, max int) []int
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/random"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result := random.RandUniqueIntSlice(5, 0, 10)
|
||||
fmt.Println(result) //[0 4 7 1 5] (random)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -896,18 +896,18 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -968,18 +968,18 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -897,18 +897,18 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
result, ok := slice.FindBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -969,18 +969,18 @@ import (
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
result, ok := slice.FindLastBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -687,16 +687,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := FromSlice([]int{3, 2, 1})
|
||||
original := stream.FromSlice([]int{3, 2, 1})
|
||||
|
||||
result, ok := original.FindLast()
|
||||
result, ok := original.FindLast()
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -687,16 +687,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
original := FromSlice([]int{3, 2, 1})
|
||||
original := stream.FromSlice([]int{3, 2, 1})
|
||||
|
||||
result, ok := original.FindLast()
|
||||
result, ok := original.FindLast()
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
fmt.Println(result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
// Output:
|
||||
// 1
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index:
|
||||
|
||||
- [Tag](#Tag)
|
||||
- [Name](#Name)
|
||||
- [Value](#Value)
|
||||
@@ -57,24 +58,24 @@ func (f *Field) Tag() *Tag
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
tag := n.Tag()
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
tag := n.Tag()
|
||||
|
||||
fmt.Println(tag.Name)
|
||||
|
||||
// Output:
|
||||
// name
|
||||
fmt.Println(tag.Name)
|
||||
|
||||
// Output:
|
||||
// name
|
||||
}
|
||||
```
|
||||
|
||||
@@ -94,23 +95,23 @@ func (f *Field) Value() any
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
|
||||
fmt.Println(n.Value())
|
||||
|
||||
// Output:
|
||||
// 111
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
|
||||
fmt.Println(n.Value())
|
||||
|
||||
// Output:
|
||||
// 111
|
||||
}
|
||||
```
|
||||
|
||||
@@ -130,32 +131,32 @@ func (f *Field) IsEmbedded() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
}
|
||||
type Child struct {
|
||||
Parent
|
||||
Age int
|
||||
}
|
||||
c1 := &Child{}
|
||||
c1.Name = "111"
|
||||
c1.Age = 11
|
||||
type Parent struct {
|
||||
Name string
|
||||
}
|
||||
type Child struct {
|
||||
Parent
|
||||
Age int
|
||||
}
|
||||
c1 := &Child{}
|
||||
c1.Name = "111"
|
||||
c1.Age = 11
|
||||
|
||||
s := structs.New(c1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsEmbedded())
|
||||
fmt.Println(a.IsEmbedded())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
s := structs.New(c1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsEmbedded())
|
||||
fmt.Println(a.IsEmbedded())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -175,26 +176,26 @@ func (f *Field) IsExported() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
age int
|
||||
}
|
||||
p1 := &Parent{Name: "11", age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("age")
|
||||
|
||||
fmt.Println(n.IsExported())
|
||||
fmt.Println(a.IsExported())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
type Parent struct {
|
||||
Name string
|
||||
age int
|
||||
}
|
||||
p1 := &Parent{Name: "11", age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("age")
|
||||
|
||||
fmt.Println(n.IsExported())
|
||||
fmt.Println(a.IsExported())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -214,26 +215,26 @@ func (f *Field) IsZero() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsZero())
|
||||
fmt.Println(a.IsZero())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsZero())
|
||||
fmt.Println(a.IsZero())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -253,26 +254,26 @@ func (f *Field) Name() string
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Name())
|
||||
fmt.Println(a.Name())
|
||||
|
||||
// Output:
|
||||
// Name
|
||||
// Age
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Name())
|
||||
fmt.Println(a.Name())
|
||||
|
||||
// Output:
|
||||
// Name
|
||||
// Age
|
||||
}
|
||||
```
|
||||
|
||||
@@ -292,26 +293,26 @@ func (f *Field) Kind() reflect.Kind
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Kind())
|
||||
fmt.Println(a.Kind())
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// int
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Kind())
|
||||
fmt.Println(a.Kind())
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// int
|
||||
}
|
||||
```
|
||||
|
||||
@@ -331,23 +332,23 @@ func (f *Field) IsSlice() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(a.IsSlice())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(a.IsSlice())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -57,24 +57,24 @@ func (f *Field) Tag() *Tag
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
tag := n.Tag()
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
tag := n.Tag()
|
||||
|
||||
fmt.Println(tag.Name)
|
||||
|
||||
// Output:
|
||||
// name
|
||||
fmt.Println(tag.Name)
|
||||
|
||||
// Output:
|
||||
// name
|
||||
}
|
||||
```
|
||||
|
||||
@@ -94,23 +94,23 @@ func (f *Field) Value() any
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
type Parent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
p1 := &Parent{"111"}
|
||||
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
|
||||
fmt.Println(n.Value())
|
||||
|
||||
// Output:
|
||||
// 111
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
|
||||
fmt.Println(n.Value())
|
||||
|
||||
// Output:
|
||||
// 111
|
||||
}
|
||||
```
|
||||
|
||||
@@ -130,32 +130,32 @@ func (f *Field) IsEmbedded() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
}
|
||||
type Child struct {
|
||||
Parent
|
||||
Age int
|
||||
}
|
||||
c1 := &Child{}
|
||||
c1.Name = "111"
|
||||
c1.Age = 11
|
||||
type Parent struct {
|
||||
Name string
|
||||
}
|
||||
type Child struct {
|
||||
Parent
|
||||
Age int
|
||||
}
|
||||
c1 := &Child{}
|
||||
c1.Name = "111"
|
||||
c1.Age = 11
|
||||
|
||||
s := structs.New(c1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsEmbedded())
|
||||
fmt.Println(a.IsEmbedded())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
s := structs.New(c1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsEmbedded())
|
||||
fmt.Println(a.IsEmbedded())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -175,26 +175,26 @@ func (f *Field) IsExported() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
age int
|
||||
}
|
||||
p1 := &Parent{Name: "11", age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("age")
|
||||
|
||||
fmt.Println(n.IsExported())
|
||||
fmt.Println(a.IsExported())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
type Parent struct {
|
||||
Name string
|
||||
age int
|
||||
}
|
||||
p1 := &Parent{Name: "11", age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("age")
|
||||
|
||||
fmt.Println(n.IsExported())
|
||||
fmt.Println(a.IsExported())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -214,26 +214,26 @@ func (f *Field) IsZero() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsZero())
|
||||
fmt.Println(a.IsZero())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.IsZero())
|
||||
fmt.Println(a.IsZero())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -253,26 +253,26 @@ func (f *Field) Name() string
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Name())
|
||||
fmt.Println(a.Name())
|
||||
|
||||
// Output:
|
||||
// Name
|
||||
// Age
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Name())
|
||||
fmt.Println(a.Name())
|
||||
|
||||
// Output:
|
||||
// Name
|
||||
// Age
|
||||
}
|
||||
```
|
||||
|
||||
@@ -292,26 +292,26 @@ func (f *Field) Kind() reflect.Kind
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Kind())
|
||||
fmt.Println(a.Kind())
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// int
|
||||
type Parent struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
p1 := &Parent{Age: 11}
|
||||
s := structs.New(p1)
|
||||
n, _ := s.Field("Name")
|
||||
a, _ := s.Field("Age")
|
||||
|
||||
fmt.Println(n.Kind())
|
||||
fmt.Println(a.Kind())
|
||||
|
||||
// Output:
|
||||
// string
|
||||
// int
|
||||
}
|
||||
```
|
||||
|
||||
@@ -331,23 +331,23 @@ func (f *Field) IsSlice() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
type Parent struct {
|
||||
Name string
|
||||
arr []int
|
||||
}
|
||||
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(a.IsSlice())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
p1 := &Parent{arr: []int{1, 2, 3}}
|
||||
s := structs.New(p1)
|
||||
a, _ := s.Field("arr")
|
||||
|
||||
fmt.Println(a.IsSlice())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index:
|
||||
|
||||
- [New](#New)
|
||||
- [ToMap](#ToMap)
|
||||
- [Fields](#Fields)
|
||||
@@ -47,16 +48,16 @@ func New(value any, tagName ...string) *Struct
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
// to do something
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
// to do something
|
||||
}
|
||||
```
|
||||
|
||||
@@ -82,29 +83,29 @@ func ToMap(v any) (map[string]any, error)
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
// use constructor function
|
||||
s1 := structs.New(p1)
|
||||
m1, _ := s1.ToMap()
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
// use constructor function
|
||||
s1 := structs.New(p1)
|
||||
m1, _ := s1.ToMap()
|
||||
|
||||
fmt.Println(m1)
|
||||
|
||||
// use static function
|
||||
m2, _ := structs.ToMap(p1)
|
||||
|
||||
fmt.Println(m2)
|
||||
|
||||
// Output:
|
||||
// map[name:11]
|
||||
// map[name:11]
|
||||
fmt.Println(m1)
|
||||
|
||||
// use static function
|
||||
m2, _ := structs.ToMap(p1)
|
||||
|
||||
fmt.Println(m2)
|
||||
|
||||
// Output:
|
||||
// map[name:11]
|
||||
// map[name:11]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -124,22 +125,22 @@ func (s *Struct) Fields() []*Field
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
fields := s.Fields()
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
fields := s.Fields()
|
||||
|
||||
fmt.Println(len(fields))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
fmt.Println(len(fields))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -159,22 +160,22 @@ func (s *Struct) Field(name string) *Field
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
f := s.Field("Name")
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
f := s.Field("Name")
|
||||
|
||||
fmt.Println(f.Value())
|
||||
|
||||
// Output:
|
||||
// 11
|
||||
fmt.Println(f.Value())
|
||||
|
||||
// Output:
|
||||
// 11
|
||||
}
|
||||
```
|
||||
|
||||
@@ -194,20 +195,20 @@ func (s *Struct) IsStruct() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
|
||||
fmt.Println(s.IsStruct())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
fmt.Println(s.IsStruct())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录:
|
||||
|
||||
- [New](#New)
|
||||
- [ToMap](#ToMap)
|
||||
- [Fields](#Fields)
|
||||
@@ -47,16 +48,16 @@ func New(value any, tagName ...string) *Struct
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
// to do something
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
// to do something
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +71,7 @@ func main() {
|
||||
func (s *Struct) ToMap() (map[string]any, error)
|
||||
```
|
||||
|
||||
<b>除此之外,提供一个便捷的静态方法ToMap</b>
|
||||
<b>除此之外,提供一个便捷的静态方法 ToMap</b>
|
||||
|
||||
```go
|
||||
func ToMap(v any) (map[string]any, error)
|
||||
@@ -82,28 +83,28 @@ func ToMap(v any) (map[string]any, error)
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s1 := structs.New(p1)
|
||||
m1, _ := s1.ToMap()
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s1 := structs.New(p1)
|
||||
m1, _ := s1.ToMap()
|
||||
|
||||
fmt.Println(m1)
|
||||
|
||||
// 如果不需要Struct更多的方法,可以直接使用ToMap
|
||||
m2, _ := structs.ToMap(p1)
|
||||
|
||||
fmt.Println(m2)
|
||||
|
||||
// Output:
|
||||
// map[name:11]
|
||||
// map[name:11]
|
||||
fmt.Println(m1)
|
||||
|
||||
// 如果不需要Struct更多的方法,可以直接使用ToMap
|
||||
m2, _ := structs.ToMap(p1)
|
||||
|
||||
fmt.Println(m2)
|
||||
|
||||
// Output:
|
||||
// map[name:11]
|
||||
// map[name:11]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -123,22 +124,22 @@ func (s *Struct) Fields() []*Field
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
fields := s.Fields()
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
fields := s.Fields()
|
||||
|
||||
fmt.Println(len(fields))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
fmt.Println(len(fields))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -158,22 +159,22 @@ func (s *Struct) Field(name string) *Field
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
f := s.Field("Name")
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
f := s.Field("Name")
|
||||
|
||||
fmt.Println(f.Value())
|
||||
|
||||
// Output:
|
||||
// 11
|
||||
fmt.Println(f.Value())
|
||||
|
||||
// Output:
|
||||
// 11
|
||||
}
|
||||
```
|
||||
|
||||
@@ -193,20 +194,20 @@ func (s *Struct) IsStruct() bool
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/structs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
p1 := &People{Name: "11"}
|
||||
s := structs.New(p1)
|
||||
|
||||
fmt.Println(s.IsStruct())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
fmt.Println(s.IsStruct())
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
290
docs/strutil.md
290
docs/strutil.md
@@ -55,6 +55,10 @@ import (
|
||||
- [ReplaceWithMap](#ReplaceWithMap)
|
||||
- [Trim](#Trim)
|
||||
- [SplitAndTrim](#SplitAndTrim)
|
||||
- [HideString](#HideString)
|
||||
- [ContainsAll](#ContainsAll)
|
||||
- [ContainsAny](#ContainsAny)
|
||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -998,14 +1002,14 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.StringToBytes("abc")
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1029,12 +1033,12 @@ import (
|
||||
|
||||
func main() {
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
result := strutil.BytesToString(bytes)
|
||||
result := strutil.BytesToString(bytes)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1058,17 +1062,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.IsBlank("")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1092,14 +1096,14 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1123,14 +1127,14 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1155,24 +1159,24 @@ import (
|
||||
func main() {
|
||||
str := "foo bar hello world"
|
||||
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1196,16 +1200,16 @@ import (
|
||||
|
||||
func main() {
|
||||
str := "ac ab ab ac"
|
||||
replaces := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
replaces := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
result := strutil.ReplaceWithMap(str, replaces)
|
||||
result := strutil.ReplaceWithMap(str, replaces)
|
||||
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// 1c 12 12 1c
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// 1c 12 12 1c
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1230,23 +1234,22 @@ import (
|
||||
func main() {
|
||||
result1 := strutil.Trim("\nabcd")
|
||||
|
||||
str := "$ ab cd $ "
|
||||
str := "$ ab cd $ "
|
||||
|
||||
result2 := strutil.Trim(str)
|
||||
result3 := strutil.Trim(str, "$")
|
||||
result2 := strutil.Trim(str)
|
||||
result3 := strutil.Trim(str, "$")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abcd
|
||||
// $ ab cd $
|
||||
// ab cd
|
||||
// Output:
|
||||
// abcd
|
||||
// $ ab cd $
|
||||
// ab cd
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitAndTrim">SplitAndTrim</span>
|
||||
|
||||
<p>Splits string `str` by a string `delimiter` to a slice, and calls Trim to every element of slice. It ignores the elements which are empty after Trim.</p>
|
||||
@@ -1268,14 +1271,155 @@ import (
|
||||
func main() {
|
||||
str := " a,b, c,d,$1 "
|
||||
|
||||
result1 := strutil.SplitAndTrim(str, ",")
|
||||
result2 := strutil.SplitAndTrim(str, ",", "$")
|
||||
result1 := strutil.SplitAndTrim(str, ",")
|
||||
result2 := strutil.SplitAndTrim(str, ",", "$")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [a b c d $1]
|
||||
// [a b c d 1]
|
||||
// Output:
|
||||
// [a b c d $1]
|
||||
// [a b c d 1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HideString">HideString</span>
|
||||
|
||||
<p>Hide some chars in source string with param `replaceChar`. replace range is origin[start : end]. [start, end).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func HideString(origin string, start, end int, replaceChar string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "13242658976"
|
||||
|
||||
result1 := strutil.HideString(str, 3, 3, "*")
|
||||
result2 := strutil.HideString(str, 3, 4, "*")
|
||||
result3 := strutil.HideString(str, 3, 7, "*")
|
||||
result4 := strutil.HideString(str, 7, 11, "*")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 13242658976
|
||||
// 132*2658976
|
||||
// 132****8976
|
||||
// 1324265****
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ContainsAll">ContainsAll</span>
|
||||
|
||||
<p>Return true if target string contains all the substrings.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ContainsAll(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := strutil.ContainsAll(str, []string{"hello", "world"})
|
||||
result2 := strutil.ContainsAll(str, []string{"hello", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ContainsAny">ContainsAny</span>
|
||||
|
||||
<p>Return true if target string contains any one of the substrings.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ContainsAny(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := strutil.ContainsAny(str, []string{"hello", "world"})
|
||||
result2 := strutil.ContainsAny(str, []string{"hello", "abc"})
|
||||
result3 := strutil.ContainsAny(str, []string{"123", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span>
|
||||
|
||||
<p>Remove whitespace characters from a string. when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func RemoveWhiteSpace(str string, repalceAll bool) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := " hello \r\n \t world"
|
||||
|
||||
result1 := strutil.RemoveWhiteSpace(str, true)
|
||||
result2 := strutil.RemoveWhiteSpace(str, false)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// helloworld
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
@@ -55,6 +55,10 @@ import (
|
||||
- [ReplaceWithMap](#ReplaceWithMap)
|
||||
- [Trim](#Trim)
|
||||
- [SplitAndTrim](#SplitAndTrim)
|
||||
- [HideString](#HideString)
|
||||
- [ContainsAll](#ContainsAll)
|
||||
- [ContainsAny](#ContainsAny)
|
||||
- [RemoveWhiteSpace](#RemoveWhiteSpace)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -971,7 +975,7 @@ func main() {
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
// 你好😄
|
||||
@@ -998,13 +1002,13 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.StringToBytes("abc")
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1028,12 +1032,12 @@ import (
|
||||
|
||||
func main() {
|
||||
bytes := []byte{'a', 'b', 'c'}
|
||||
result := strutil.BytesToString(bytes)
|
||||
result := strutil.BytesToString(bytes)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1057,17 +1061,17 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.IsBlank("")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
result2 := strutil.IsBlank("\t\v\f\n")
|
||||
result3 := strutil.IsBlank(" 中文")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1091,14 +1095,14 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1122,14 +1126,14 @@ import (
|
||||
|
||||
func main() {
|
||||
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1154,28 +1158,27 @@ import (
|
||||
func main() {
|
||||
str := "foo bar hello world"
|
||||
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
result1 := strutil.IndexOffset(str, "o", 5)
|
||||
result2 := strutil.IndexOffset(str, "o", 0)
|
||||
result3 := strutil.IndexOffset(str, "d", len(str)-1)
|
||||
result4 := strutil.IndexOffset(str, "d", len(str))
|
||||
result5 := strutil.IndexOffset(str, "f", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
// Output:
|
||||
// 12
|
||||
// 1
|
||||
// 18
|
||||
// -1
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ReplaceWithMap">ReplaceWithMap</span>
|
||||
|
||||
<p>返回`str`的副本,以无序的方式被map替换,区分大小写。</p>
|
||||
@@ -1196,16 +1199,16 @@ import (
|
||||
|
||||
func main() {
|
||||
str := "ac ab ab ac"
|
||||
replaces := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
replaces := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
result := strutil.ReplaceWithMap(str, replaces)
|
||||
result := strutil.ReplaceWithMap(str, replaces)
|
||||
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// 1c 12 12 1c
|
||||
fmt.Println(result)
|
||||
// Output:
|
||||
// 1c 12 12 1c
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1230,23 +1233,22 @@ import (
|
||||
func main() {
|
||||
result1 := strutil.Trim("\nabcd")
|
||||
|
||||
str := "$ ab cd $ "
|
||||
str := "$ ab cd $ "
|
||||
|
||||
result2 := strutil.Trim(str)
|
||||
result3 := strutil.Trim(str, "$")
|
||||
result2 := strutil.Trim(str)
|
||||
result3 := strutil.Trim(str, "$")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abcd
|
||||
// $ ab cd $
|
||||
// ab cd
|
||||
// Output:
|
||||
// abcd
|
||||
// $ ab cd $
|
||||
// ab cd
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitAndTrim">SplitAndTrim</span>
|
||||
|
||||
<p>将字符串str按字符串delimiter拆分为一个切片,并对该数组的每个元素调用Trim。忽略Trim后为空的元素。</p>
|
||||
@@ -1268,14 +1270,155 @@ import (
|
||||
func main() {
|
||||
str := " a,b, c,d,$1 "
|
||||
|
||||
result1 := strutil.SplitAndTrim(str, ",")
|
||||
result2 := strutil.SplitAndTrim(str, ",", "$")
|
||||
result1 := strutil.SplitAndTrim(str, ",")
|
||||
result2 := strutil.SplitAndTrim(str, ",", "$")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [a b c d $1]
|
||||
// [a b c d 1]
|
||||
// Output:
|
||||
// [a b c d $1]
|
||||
// [a b c d 1]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="HideString">HideString</span>
|
||||
|
||||
<p>使用参数`replaceChar`隐藏源字符串中的一些字符。替换范围是 origin[start : end]。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HideString(origin string, start, end int, replaceChar string) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "13242658976"
|
||||
|
||||
result1 := strutil.HideString(str, 3, 3, "*")
|
||||
result2 := strutil.HideString(str, 3, 4, "*")
|
||||
result3 := strutil.HideString(str, 3, 7, "*")
|
||||
result4 := strutil.HideString(str, 7, 11, "*")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 13242658976
|
||||
// 132*2658976
|
||||
// 132****8976
|
||||
// 1324265****
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ContainsAll">ContainsAll</span>
|
||||
|
||||
<p>判断字符串是否包括全部给定的子字符串切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ContainsAll(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := strutil.ContainsAll(str, []string{"hello", "world"})
|
||||
result2 := strutil.ContainsAll(str, []string{"hello", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ContainsAny">ContainsAny</span>
|
||||
|
||||
<p>判断字符串是否包括给定的子字符串切片中任意一个子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ContainsAny(str string, substrs []string) bool
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := strutil.ContainsAny(str, []string{"hello", "world"})
|
||||
result2 := strutil.ContainsAny(str, []string{"hello", "abc"})
|
||||
result3 := strutil.ContainsAny(str, []string{"123", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RemoveWhiteSpace">RemoveWhiteSpace</span>
|
||||
|
||||
<p>删除字符串中的空格,当设置repalceAll为true时,删除全部空格,为false时,替换多个空格为1个空格。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func RemoveWhiteSpace(str string, repalceAll bool) string
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := " hello \r\n \t world"
|
||||
|
||||
result1 := strutil.RemoveWhiteSpace(str, true)
|
||||
result2 := strutil.RemoveWhiteSpace(str, false)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// helloworld
|
||||
// hello world
|
||||
}
|
||||
```
|
||||
|
||||
142
fileutil/file.go
142
fileutil/file.go
@@ -208,7 +208,11 @@ func Zip(fpath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
return addFileToArchive(fpath, archive)
|
||||
}
|
||||
|
||||
func addFileToArchive(fpath string, archive *zip.Writer) error {
|
||||
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -224,32 +228,22 @@ func Zip(fpath string, destPath string) error {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
}
|
||||
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(writer, file)
|
||||
if err != nil {
|
||||
if _, err := io.Copy(writer, file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath.
|
||||
@@ -302,6 +296,64 @@ func UnZip(zipFile string, destPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
|
||||
// Play: https://go.dev/play/p/cxvaT8TRNQp
|
||||
func ZipAppendEntry(fpath string, destPath string) error {
|
||||
tempFile, err := os.CreateTemp("", "temp.zip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
zipReader, err := zip.OpenReader(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archive := zip.NewWriter(tempFile)
|
||||
|
||||
for _, zipItem := range zipReader.File {
|
||||
zipItemReader, err := zipItem.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header, err := zip.FileInfoHeader(zipItem.FileInfo())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = zipItem.Name
|
||||
targetItem, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(targetItem, zipItemReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = addFileToArchive(fpath, archive)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = zipReader.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = archive.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tempFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CopyFile(tempFile.Name(), destPath)
|
||||
}
|
||||
|
||||
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
relPath, err := filepath.Rel(".", path2)
|
||||
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||
@@ -402,7 +454,7 @@ func MTime(filepath string) (int64, error) {
|
||||
return f.ModTime().Unix(), nil
|
||||
}
|
||||
|
||||
// MTime returns file sha value, param `shaType` should be 1, 256 or 512.
|
||||
// Sha returns file sha value, param `shaType` should be 1, 256 or 512.
|
||||
// Play: https://go.dev/play/p/VfEEcO2MJYf
|
||||
func Sha(filepath string, shaType ...int) (string, error) {
|
||||
file, err := os.Open(filepath)
|
||||
@@ -453,3 +505,57 @@ func ReadCsvFile(filepath string) ([][]string, error) {
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// WriteCsvFile write content to target csv file.
|
||||
// Play: https://go.dev/play/p/dAXm58Q5U1o
|
||||
func WriteCsvFile(filepath string, records [][]string, append bool) error {
|
||||
flag := os.O_RDWR | os.O_CREATE
|
||||
|
||||
if append {
|
||||
flag = flag | os.O_APPEND
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(filepath, flag, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
writer := csv.NewWriter(f)
|
||||
writer.Comma = ','
|
||||
|
||||
return writer.WriteAll(records)
|
||||
}
|
||||
|
||||
// WriteStringToFile write string to target file.
|
||||
// Play: https://go.dev/play/p/GhLS6d8lH_g
|
||||
func WriteStringToFile(filepath string, content string, append bool) error {
|
||||
flag := os.O_RDWR | os.O_CREATE
|
||||
if append {
|
||||
flag = flag | os.O_APPEND
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(filepath, flag, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(content)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteBytesToFile write bytes to target file.
|
||||
// Play: https://go.dev/play/p/s7QlDxMj3P8
|
||||
func WriteBytesToFile(filepath string, content []byte) error {
|
||||
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write(content)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -175,11 +175,11 @@ func ExampleReadFileByLine() {
|
||||
}
|
||||
|
||||
func ExampleListFileNames() {
|
||||
fileList, _ := ListFileNames("./")
|
||||
fileList, _ := ListFileNames("../internal")
|
||||
fmt.Println(fileList)
|
||||
|
||||
// Output:
|
||||
// [file.go file_example_test.go file_test.go]
|
||||
// [assert.go assert_test.go error_join.go]
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
@@ -224,6 +224,28 @@ func ExampleUnZip() {
|
||||
// application/octet-stream
|
||||
}
|
||||
|
||||
func ExampleZipAppendEntry() {
|
||||
zipFile := "./test.zip"
|
||||
CopyFile("./testdata/file.go.zip", zipFile)
|
||||
|
||||
ZipAppendEntry("./testdata", zipFile)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
UnZip(zipFile, unZipPath)
|
||||
|
||||
fmt.Println(IsExist("./unzip/file.go"))
|
||||
fmt.Println(IsExist("./unzip/testdata/file.go.zip"))
|
||||
fmt.Println(IsExist("./unzip/testdata/test.txt"))
|
||||
|
||||
os.Remove(zipFile)
|
||||
os.RemoveAll(unZipPath)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsZipFile() {
|
||||
result1 := IsZipFile("./file.go")
|
||||
result2 := IsZipFile("./testdata/file.go.zip")
|
||||
@@ -276,7 +298,7 @@ func ExampleSha() {
|
||||
}
|
||||
|
||||
func ExampleReadCsvFile() {
|
||||
content, err := ReadCsvFile("./testdata/test.csv")
|
||||
content, err := ReadCsvFile("./testdata/demo.csv")
|
||||
|
||||
fmt.Println(content)
|
||||
fmt.Println(err)
|
||||
@@ -285,3 +307,75 @@ func ExampleReadCsvFile() {
|
||||
// [[Bob 12 male] [Duke 14 male] [Lucy 16 female]]
|
||||
// <nil>
|
||||
}
|
||||
|
||||
func ExampleWriteCsvFile() {
|
||||
data := [][]string{
|
||||
{"Lili", "22", "female"},
|
||||
{"Jim", "21", "male"},
|
||||
}
|
||||
err := WriteCsvFile("./testdata/test2.csv", data, false)
|
||||
fmt.Println(err)
|
||||
|
||||
content, _ := ReadCsvFile("./testdata/test2.csv")
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// <nil>
|
||||
// [[Lili 22 female] [Jim 21 male]]
|
||||
}
|
||||
|
||||
func ExampleWriteStringToFile() {
|
||||
filepath := "./test.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteStringToFile(filepath, "hello", true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleWriteBytesToFile() {
|
||||
filepath := "./bytes.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteBytesToFile(filepath, []byte("hello"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
os.Remove(filepath)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
@@ -191,6 +191,44 @@ func TestZipAndUnZip(t *testing.T) {
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestZipAppendEntry(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestZipAppendEntry")
|
||||
|
||||
zipFile := "./text.zip"
|
||||
err := CopyFile("./testdata/file.go.zip", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
|
||||
_, err = file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
file.Close()
|
||||
|
||||
err = ZipAppendEntry(srcFile, zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = ZipAppendEntry("./testdata", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
err = UnZip(zipFile, unZipPath)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, IsExist("./unzip/text.txt"))
|
||||
assert.Equal(true, IsExist("./unzip/file.go"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestFileMode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileMode")
|
||||
|
||||
@@ -235,10 +273,10 @@ func TestMiMeType(t *testing.T) {
|
||||
func TestListFileNames(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListFileNames")
|
||||
|
||||
filesInPath, err := ListFileNames("./")
|
||||
filesInPath, err := ListFileNames("../internal")
|
||||
assert.IsNil(err)
|
||||
|
||||
expected := []string{"file.go", "file_example_test.go", "file_test.go"}
|
||||
expected := []string{"assert.go", "assert_test.go", "error_join.go"}
|
||||
assert.Equal(expected, filesInPath)
|
||||
}
|
||||
|
||||
@@ -288,7 +326,7 @@ func TestSha(t *testing.T) {
|
||||
func TestReadCsvFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReadCsvFile")
|
||||
|
||||
content, err := ReadCsvFile("./testdata/test.csv")
|
||||
content, err := ReadCsvFile("./testdata/demo.csv")
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
@@ -296,3 +334,91 @@ func TestReadCsvFile(t *testing.T) {
|
||||
assert.Equal(3, len(content[0]))
|
||||
assert.Equal("Bob", content[0][0])
|
||||
}
|
||||
|
||||
func TestWriteCsvFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteCsvFile")
|
||||
|
||||
csvFilePath := "./testdata/test1.csv"
|
||||
content := [][]string{
|
||||
{"Lili", "22", "female"},
|
||||
{"Jim", "21", "male"},
|
||||
}
|
||||
|
||||
err := WriteCsvFile(csvFilePath, content, false)
|
||||
assert.IsNil(err)
|
||||
|
||||
readContent, err := ReadCsvFile(csvFilePath)
|
||||
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(2, len(readContent))
|
||||
assert.Equal(3, len(readContent[0]))
|
||||
assert.Equal("Lili", content[0][0])
|
||||
|
||||
// RemoveFile(csvFilePath)
|
||||
}
|
||||
|
||||
func TestWriteStringToFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteStringToFile")
|
||||
|
||||
filepath := "./test.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteStringToFile(filepath, "hello", false)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content1, err := ReadFileToString(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
err = WriteStringToFile(filepath, " world", true)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content2, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
assert.Equal("hello", content1)
|
||||
assert.Equal("hello world", string(content2))
|
||||
|
||||
os.Remove(filepath)
|
||||
}
|
||||
|
||||
func TestWriteBytesToFile(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWriteBytesToFile")
|
||||
|
||||
filepath := "./bytes.txt"
|
||||
|
||||
file, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = WriteBytesToFile(filepath, []byte("hello"))
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
assert.Equal("hello", string(content))
|
||||
|
||||
os.Remove(filepath)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Bob, 12, male
|
||||
Duke, 14, male
|
||||
Lucy, 16, female
|
||||
Lucy, 16, female
|
||||
|
2
fileutil/testdata/test1.csv
vendored
Normal file
2
fileutil/testdata/test1.csv
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Lili,22,female
|
||||
Jim,21,male
|
||||
|
2
fileutil/testdata/test2.csv
vendored
Normal file
2
fileutil/testdata/test2.csv
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Lili,22,female
|
||||
Jim,21,male
|
||||
|
@@ -55,7 +55,7 @@ func Factorial(x uint) uint {
|
||||
}
|
||||
|
||||
// Percent calculate the percentage of value to total.
|
||||
// Play: https://go.dev/play/p/QQM9B13coSP
|
||||
// Play: https://go.dev/play/p/s0NdFCtwuyd
|
||||
func Percent(val, total float64, n int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
@@ -172,6 +172,18 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// Sum return sum of passed numbers.
|
||||
// Play: https://go.dev/play/p/1To2ImAMJA7
|
||||
func Sum[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
var sum T
|
||||
|
||||
for _, v := range numbers {
|
||||
sum += v
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
// Average return average value of numbers.
|
||||
// Play: https://go.dev/play/p/Vv7LBwER-pz
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
@@ -258,7 +270,7 @@ func IsPrime(n int) bool {
|
||||
}
|
||||
|
||||
// GCD return greatest common divisor (GCD) of integers.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/CiEceLSoAKB
|
||||
func GCD[T constraints.Integer](integers ...T) T {
|
||||
result := integers[0]
|
||||
|
||||
@@ -283,7 +295,7 @@ func gcd[T constraints.Integer](a, b T) T {
|
||||
}
|
||||
|
||||
// LCM return Least Common Multiple (LCM) of integers.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/EjcZxfY7G_g
|
||||
func LCM[T constraints.Integer](integers ...T) T {
|
||||
result := integers[0]
|
||||
|
||||
@@ -301,3 +313,41 @@ func lcm[T constraints.Integer](a, b T) T {
|
||||
}
|
||||
return a * b / gcd(a, b)
|
||||
}
|
||||
|
||||
// Cos returns the cosine of the radian argument.
|
||||
// Play: https://go.dev/play/p/Sm89LoIfvFq
|
||||
func Cos(radian float64, precision ...int) float64 {
|
||||
t := 1.0 / (2.0 * math.Pi)
|
||||
radian *= t
|
||||
radian -= 0.25 + math.Floor(radian+0.25)
|
||||
radian *= 16.0 * (math.Abs(radian) - 0.5)
|
||||
radian += 0.225 * radian * (math.Abs(radian) - 1.0)
|
||||
|
||||
if len(precision) == 1 {
|
||||
return TruncRound(radian, precision[0])
|
||||
}
|
||||
|
||||
return TruncRound(radian, 3)
|
||||
}
|
||||
|
||||
// Cos returns the sine of the radian argument.
|
||||
// Play: https://go.dev/play/p/TWMQlMywDsP
|
||||
func Sin(radian float64, precision ...int) float64 {
|
||||
return Cos((math.Pi / 2) - radian)
|
||||
}
|
||||
|
||||
// Log returns the logarithm of base n.
|
||||
// Play: https://go.dev/play/p/_d4bi8oyhat
|
||||
func Log(n, base float64) float64 {
|
||||
return math.Log(n) / math.Log(base)
|
||||
}
|
||||
|
||||
// Abs returns the absolute value of x.
|
||||
// Play: todo
|
||||
func Abs[T constraints.Integer | constraints.Float](x T) T {
|
||||
if x < 0 {
|
||||
return (-x)
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -122,6 +122,18 @@ func ExampleAverage() {
|
||||
// 1.3
|
||||
}
|
||||
|
||||
func ExampleSum() {
|
||||
result1 := Sum(1, 2)
|
||||
result2 := Sum(0.1, float64(1))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.1
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result1 := Max(1, 2, 3)
|
||||
result2 := Max(1.2, 1.4, 1.1, 1.4)
|
||||
@@ -320,3 +332,75 @@ func ExampleLCM() {
|
||||
// 2
|
||||
// 18
|
||||
}
|
||||
|
||||
func ExampleCos() {
|
||||
result1 := Cos(0)
|
||||
result2 := Cos(90)
|
||||
result3 := Cos(180)
|
||||
result4 := Cos(math.Pi)
|
||||
result5 := Cos(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -0.447
|
||||
// -0.598
|
||||
// -1
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleSin() {
|
||||
result1 := Sin(0)
|
||||
result2 := Sin(90)
|
||||
result3 := Sin(180)
|
||||
result4 := Sin(math.Pi)
|
||||
result5 := Sin(math.Pi / 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0.894
|
||||
// -0.801
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleLog() {
|
||||
result1 := Log(8, 2)
|
||||
result2 := TruncRound(Log(5, 2), 2)
|
||||
result3 := TruncRound(Log(27, 3), 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 2.32
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleAbs() {
|
||||
result1 := Abs(-1)
|
||||
result2 := Abs(-0.1)
|
||||
result3 := Abs(float32(0.2))
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 0.1
|
||||
// 0.2
|
||||
}
|
||||
|
||||
@@ -44,53 +44,61 @@ func TestPercent(t *testing.T) {
|
||||
func TestRoundToFloat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRoundToFloat")
|
||||
|
||||
assert.Equal(RoundToFloat(0, 0), float64(0))
|
||||
assert.Equal(RoundToFloat(0, 1), float64(0))
|
||||
assert.Equal(RoundToFloat(0.124, 2), float64(0.12))
|
||||
assert.Equal(RoundToFloat(0.125, 2), float64(0.13))
|
||||
assert.Equal(RoundToFloat(0.125, 3), float64(0.125))
|
||||
assert.Equal(RoundToFloat(33.33333, 2), float64(33.33))
|
||||
assert.Equal(float64(0), RoundToFloat(0, 0))
|
||||
assert.Equal(float64(0), RoundToFloat(0, 1))
|
||||
assert.Equal(0.12, RoundToFloat(0.124, 2))
|
||||
assert.Equal(0.13, RoundToFloat(0.125, 2))
|
||||
assert.Equal(0.125, RoundToFloat(0.125, 3))
|
||||
assert.Equal(33.33, RoundToFloat(33.33333, 2))
|
||||
}
|
||||
|
||||
func TestRoundToString(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRoundToString")
|
||||
|
||||
assert.Equal(RoundToString(0, 0), "0")
|
||||
assert.Equal(RoundToString(0, 1), "0.0")
|
||||
assert.Equal(RoundToString(0.124, 2), "0.12")
|
||||
assert.Equal(RoundToString(0.125, 2), "0.13")
|
||||
assert.Equal(RoundToString(0.125, 3), "0.125")
|
||||
assert.Equal("0", RoundToString(0, 0))
|
||||
assert.Equal("0.0", RoundToString(0, 1))
|
||||
assert.Equal("0.12", RoundToString(0.124, 2))
|
||||
assert.Equal("0.13", RoundToString(0.125, 2))
|
||||
assert.Equal("0.125", RoundToString(0.125, 3))
|
||||
}
|
||||
|
||||
func TestTruncRound(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTruncRound")
|
||||
|
||||
assert.Equal(TruncRound(0, 0), float64(0))
|
||||
assert.Equal(TruncRound(0, 1), float64(0))
|
||||
assert.Equal(TruncRound(0.124, 2), float64(0.12))
|
||||
assert.Equal(TruncRound(0.125, 2), float64(0.12))
|
||||
assert.Equal(TruncRound(0.125, 3), float64(0.125))
|
||||
assert.Equal(TruncRound(33.33333, 2), float64(33.33))
|
||||
assert.Equal(float64(0), TruncRound(0, 0))
|
||||
assert.Equal(float64(0), TruncRound(0, 1))
|
||||
assert.Equal(0.12, TruncRound(0.124, 2))
|
||||
assert.Equal(0.12, TruncRound(0.125, 2))
|
||||
assert.Equal(0.125, TruncRound(0.125, 3))
|
||||
assert.Equal(33.33, TruncRound(33.33333, 2))
|
||||
}
|
||||
|
||||
func TestAverage(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAverage")
|
||||
|
||||
assert.Equal(Average(0, 0), 0)
|
||||
assert.Equal(Average(1, 1), 1)
|
||||
assert.Equal(0, Average(0, 0))
|
||||
assert.Equal(1, Average(1, 1))
|
||||
|
||||
avg := Average(1.2, 1.4)
|
||||
assert.Equal(1.3, RoundToFloat(avg, 1))
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSum")
|
||||
|
||||
assert.Equal(1, Sum(0, 1))
|
||||
assert.Equal(1.1, Sum(0.1, float64(1)))
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMax")
|
||||
|
||||
assert.Equal(Max(0, 0), 0)
|
||||
assert.Equal(Max(1, 2, 3), 3)
|
||||
assert.Equal(Max(1.2, 1.4, 1.1, 1.4), 1.4)
|
||||
assert.Equal(0, Max(0, 0))
|
||||
assert.Equal(3, Max(1, 2, 3))
|
||||
assert.Equal(1.4, Max(1.2, 1.4, 1.1, 1.4))
|
||||
|
||||
type Integer int
|
||||
assert.Equal(Max(Integer(1), Integer(0)), Integer(1))
|
||||
assert.Equal(Integer(1), Max(Integer(1), Integer(0)))
|
||||
}
|
||||
|
||||
func TestMaxBy(t *testing.T) {
|
||||
@@ -115,9 +123,9 @@ func TestMaxBy(t *testing.T) {
|
||||
func TestMin(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMin")
|
||||
|
||||
assert.Equal(Min(0, 0), 0)
|
||||
assert.Equal(Min(1, 2, 3), 1)
|
||||
assert.Equal(Min(1.2, 1.4, 1.1, 1.4), 1.1)
|
||||
assert.Equal(0, Min(0, 0))
|
||||
assert.Equal(1, Min(1, 2, 3))
|
||||
assert.Equal(1.1, Min(1.2, 1.4, 1.1, 1.4))
|
||||
}
|
||||
|
||||
func TestMinBy(t *testing.T) {
|
||||
@@ -249,3 +257,44 @@ func TestLCM(t *testing.T) {
|
||||
assert.Equal(2, LCM(1, 2))
|
||||
assert.Equal(18, LCM(3, 6, 9))
|
||||
}
|
||||
|
||||
func TestCos(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCos")
|
||||
|
||||
assert.EqualValues(1, Cos(0))
|
||||
assert.EqualValues(-0.447, Cos(90))
|
||||
assert.EqualValues(-0.598, Cos(180))
|
||||
assert.EqualValues(-1, Cos(math.Pi))
|
||||
assert.EqualValues(0, Cos(math.Pi/2))
|
||||
}
|
||||
|
||||
func TestSin(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSin")
|
||||
|
||||
assert.EqualValues(0, Sin(0))
|
||||
assert.EqualValues(0.894, Sin(90))
|
||||
assert.EqualValues(-0.801, Sin(180))
|
||||
assert.EqualValues(0, Sin(math.Pi))
|
||||
assert.EqualValues(1, Sin(math.Pi/2))
|
||||
}
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestLog")
|
||||
|
||||
assert.EqualValues(3, Log(8, 2))
|
||||
assert.EqualValues(3, TruncRound(Log(27, 3), 0))
|
||||
assert.EqualValues(2.32, TruncRound(Log(5, 2), 2))
|
||||
}
|
||||
|
||||
func TestAbs(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAbs")
|
||||
|
||||
assert.Equal(0, Abs(0))
|
||||
assert.Equal(1, Abs(-1))
|
||||
|
||||
assert.Equal(0.1, Abs(-0.1))
|
||||
|
||||
assert.Equal(int64(1), Abs(int64(-1)))
|
||||
assert.Equal(float32(1), Abs(float32(-1)))
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -94,6 +96,7 @@ type HttpRequest struct {
|
||||
Headers http.Header
|
||||
QueryParams url.Values
|
||||
FormData url.Values
|
||||
File *File
|
||||
Body []byte
|
||||
}
|
||||
|
||||
@@ -186,7 +189,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
}
|
||||
|
||||
if request.FormData != nil {
|
||||
client.setFormData(req, request.FormData)
|
||||
if request.File != nil {
|
||||
err = client.setFormData(req, request.FormData, setFile(request.File))
|
||||
} else {
|
||||
err = client.setFormData(req, request.FormData, nil)
|
||||
}
|
||||
}
|
||||
|
||||
client.Request = req
|
||||
@@ -251,10 +258,80 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
|
||||
formData := []byte(values.Encode())
|
||||
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||
req.ContentLength = int64(len(formData))
|
||||
// setFormData set http request FormData param
|
||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values, setFile SetFileFunc) error {
|
||||
if setFile != nil {
|
||||
err := setFile(req, values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
formData := []byte(values.Encode())
|
||||
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||
req.ContentLength = int64(len(formData))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SetFileFunc func(req *http.Request, values url.Values) error
|
||||
|
||||
// File struct is a combination of file attributes
|
||||
type File struct {
|
||||
Content []byte
|
||||
Path string
|
||||
FieldName string
|
||||
FileName string
|
||||
}
|
||||
|
||||
// setFile set parameters for http request formdata file upload
|
||||
func setFile(f *File) SetFileFunc {
|
||||
return func(req *http.Request, values url.Values) error {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
for key, vals := range values {
|
||||
for _, val := range vals {
|
||||
err := writer.WriteField(key, val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.Content != nil {
|
||||
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
part.Write(f.Content)
|
||||
} else if f.Path != "" {
|
||||
file, err := os.Open(f.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(part, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := writer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Body = io.NopCloser(body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.ContentLength = int64(body.Len())
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// validateRequest check if a request has url, and valid method.
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -49,8 +53,8 @@ func TestHttpPost(t *testing.T) {
|
||||
func TestHttpPostFormData(t *testing.T) {
|
||||
apiUrl := "https://jsonplaceholder.typicode.com/todos"
|
||||
header := map[string]string{
|
||||
// "Content-Type": "application/x-www-form-urlencoded",
|
||||
"Content-Type": "multipart/form-data",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
// "Content-Type": "multipart/form-data",
|
||||
}
|
||||
|
||||
postData := url.Values{}
|
||||
@@ -61,7 +65,7 @@ func TestHttpPostFormData(t *testing.T) {
|
||||
// postData["userId"] = "1"
|
||||
// postData["title"] = "title"
|
||||
|
||||
resp, err := HttpPost(apiUrl, header, postData, nil)
|
||||
resp, err := HttpPost(apiUrl, header, nil, postData)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -245,3 +249,108 @@ func TestStructToUrlValues(t *testing.T) {
|
||||
assert.Equal("456", queryValues2.Get("userId"))
|
||||
assert.Equal("", queryValues2.Get("name"))
|
||||
}
|
||||
|
||||
func handleFileRequest(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseMultipartForm(1024)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
key1 := r.FormValue("key1")
|
||||
expectedKey1 := "value1"
|
||||
if key1 != expectedKey1 {
|
||||
t.Fatalf("expected %s, got %s", expectedKey1, key1)
|
||||
}
|
||||
|
||||
key2 := r.FormValue("key2")
|
||||
expectedKey2 := "value2"
|
||||
if key2 != expectedKey2 {
|
||||
t.Fatalf("expected %s, got %s", expectedKey2, key2)
|
||||
}
|
||||
|
||||
file, header, err := r.FormFile("image")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedFileName := "testImage.jpg"
|
||||
if header.Filename != expectedFileName {
|
||||
t.Fatalf("expected %s, got %s", expectedFileName, header.Filename)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedContent := []byte("file content")
|
||||
if !bytes.Equal(content, expectedContent) {
|
||||
t.Fatalf("expected %s, got %s", string(expectedContent), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendRequestWithFileContent(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
handleFileRequest(t, writer, request)
|
||||
})
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
client := NewHttpClient()
|
||||
request := &HttpRequest{
|
||||
RawURL: server.URL,
|
||||
Method: "POST",
|
||||
File: &File{Content: []byte("file content"), FieldName: "image", FileName: "testImage.jpg"},
|
||||
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||
}
|
||||
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendRequestWithFilePath(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
handleFileRequest(t, writer, request)
|
||||
})
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "testImage.jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
tmpFile.Write([]byte("file content"))
|
||||
tmpFile.Close()
|
||||
|
||||
client := NewHttpClient()
|
||||
request := &HttpRequest{
|
||||
RawURL: server.URL,
|
||||
Method: "POST",
|
||||
File: &File{Path: tmpFile.Name(), FieldName: "image", FileName: "testImage.jpg"},
|
||||
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||
}
|
||||
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package netutil
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -72,52 +74,34 @@ func setHeaderAndQueryParam(req *http.Request, reqUrl string, header, queryParam
|
||||
}
|
||||
|
||||
func setHeaderAndQueryAndBody(req *http.Request, reqUrl string, header, queryParam, body any) error {
|
||||
err := setHeader(req, header)
|
||||
if err != nil {
|
||||
if err := setHeader(req, header); err != nil {
|
||||
return err
|
||||
} else if err = setQueryParam(req, reqUrl, queryParam); err != nil {
|
||||
return err
|
||||
} else if err = setBodyByte(req, body); err != nil {
|
||||
return err
|
||||
}
|
||||
err = setQueryParam(req, reqUrl, queryParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") || req.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
|
||||
if formData, ok := queryParam.(url.Values); ok {
|
||||
err = setBodyByte(req, []byte(formData.Encode()))
|
||||
}
|
||||
if formData, ok := queryParam.(map[string]string); ok {
|
||||
postData := url.Values{}
|
||||
for k, v := range formData {
|
||||
postData.Set(k, v)
|
||||
}
|
||||
err = setBodyByte(req, []byte(postData.Encode()))
|
||||
}
|
||||
|
||||
} else {
|
||||
err = setBodyByte(req, body)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setHeader(req *http.Request, header any) error {
|
||||
if header != nil {
|
||||
switch v := header.(type) {
|
||||
case map[string]string:
|
||||
for k := range v {
|
||||
req.Header.Add(k, v[k])
|
||||
}
|
||||
case http.Header:
|
||||
for k, vv := range v {
|
||||
for _, vvv := range vv {
|
||||
req.Header.Add(k, vvv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("header params type should be http.Header or map[string]string")
|
||||
if header == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v := header.(type) {
|
||||
case map[string]string:
|
||||
for k := range v {
|
||||
req.Header.Add(k, v[k])
|
||||
}
|
||||
case http.Header:
|
||||
for k, vv := range v {
|
||||
for _, vvv := range vv {
|
||||
req.Header.Add(k, vvv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("header params type should be http.Header or map[string]string")
|
||||
}
|
||||
|
||||
if host := req.Header.Get("Host"); host != "" {
|
||||
@@ -137,19 +121,21 @@ func setUrl(req *http.Request, reqUrl string) error {
|
||||
}
|
||||
|
||||
func setQueryParam(req *http.Request, reqUrl string, queryParam any) error {
|
||||
if queryParam == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var values url.Values
|
||||
if queryParam != nil {
|
||||
switch v := queryParam.(type) {
|
||||
case map[string]string:
|
||||
values = url.Values{}
|
||||
for k := range v {
|
||||
values.Set(k, v[k])
|
||||
}
|
||||
case url.Values:
|
||||
values = v
|
||||
default:
|
||||
return errors.New("query string params type should be url.Values or map[string]string")
|
||||
switch v := queryParam.(type) {
|
||||
case map[string]string:
|
||||
values = url.Values{}
|
||||
for k := range v {
|
||||
values.Set(k, v[k])
|
||||
}
|
||||
case url.Values:
|
||||
values = v
|
||||
default:
|
||||
return errors.New("query string params type should be url.Values or map[string]string")
|
||||
}
|
||||
|
||||
// set url
|
||||
@@ -170,14 +156,36 @@ func setQueryParam(req *http.Request, reqUrl string, queryParam any) error {
|
||||
}
|
||||
|
||||
func setBodyByte(req *http.Request, body any) error {
|
||||
if body != nil {
|
||||
switch b := body.(type) {
|
||||
case []byte:
|
||||
req.Body = io.NopCloser(bytes.NewReader(b))
|
||||
req.ContentLength = int64(len(b))
|
||||
default:
|
||||
return errors.New("body type should be []byte")
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
var bodyReader *bytes.Reader
|
||||
switch b := body.(type) {
|
||||
case io.Reader:
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if _, err := io.Copy(buf, b); err != nil {
|
||||
return err
|
||||
}
|
||||
req.Body = ioutil.NopCloser(buf)
|
||||
req.ContentLength = int64(buf.Len())
|
||||
case []byte:
|
||||
bodyReader = bytes.NewReader(b)
|
||||
req.Body = ioutil.NopCloser(bodyReader)
|
||||
req.ContentLength = int64(bodyReader.Len())
|
||||
case map[string]interface{}:
|
||||
values := url.Values{}
|
||||
for k := range b {
|
||||
values.Set(k, fmt.Sprintf("%v", b[k]))
|
||||
}
|
||||
bodyReader = bytes.NewReader([]byte(values.Encode()))
|
||||
req.Body = ioutil.NopCloser(bodyReader)
|
||||
req.ContentLength = int64(bodyReader.Len())
|
||||
case url.Values:
|
||||
bodyReader = bytes.NewReader([]byte(b.Encode()))
|
||||
req.Body = ioutil.NopCloser(bodyReader)
|
||||
req.ContentLength = int64(bodyReader.Len())
|
||||
default:
|
||||
return fmt.Errorf("invalid body type: %T", b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license.
|
||||
|
||||
// Package pointer contains some util functions to operate go pointer.
|
||||
package pointer
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Of returns a pointer to the value `v`.
|
||||
// Play: https://go.dev/play/p/HFd70x4DrMj
|
||||
func Of[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Unwrap returns the value from the pointer.
|
||||
// Play: https://go.dev/play/p/cgeu3g7cjWb
|
||||
func Unwrap[T any](p *T) T {
|
||||
return *p
|
||||
}
|
||||
|
||||
// ExtractPointer returns the underlying value by the given interface type
|
||||
// Play: https://go.dev/play/p/D7HFjeWU2ZP
|
||||
func ExtractPointer(value any) any {
|
||||
t := reflect.TypeOf(value)
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
44
pointer/pointer_examples_test.go
Normal file
44
pointer/pointer_examples_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package pointer
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleOf() {
|
||||
result1 := Of(123)
|
||||
result2 := Of("abc")
|
||||
|
||||
fmt.Println(*result1)
|
||||
fmt.Println(*result2)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
}
|
||||
|
||||
func ExampleUnwrap() {
|
||||
a := 123
|
||||
b := "abc"
|
||||
|
||||
result1 := Unwrap(&a)
|
||||
result2 := Unwrap(&b)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// abc
|
||||
}
|
||||
|
||||
func ExampleExtractPointer() {
|
||||
a := 1
|
||||
b := &a
|
||||
c := &b
|
||||
d := &c
|
||||
|
||||
result := ExtractPointer(d)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
@@ -1,12 +1,32 @@
|
||||
package pointer
|
||||
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestExtractPointer(t *testing.T) {
|
||||
func TestOf(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestOf")
|
||||
|
||||
result1 := Of(123)
|
||||
result2 := Of("abc")
|
||||
|
||||
assert.Equal(123, *result1)
|
||||
assert.Equal("abc", *result2)
|
||||
}
|
||||
|
||||
func TestUnwrap(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestUnwrap")
|
||||
|
||||
a := 123
|
||||
b := "abc"
|
||||
|
||||
assert.Equal(a, Unwrap(&a))
|
||||
assert.Equal(b, Unwrap(&b))
|
||||
}
|
||||
|
||||
func TestExtractPointer(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestExtractPointer")
|
||||
|
||||
a := 1
|
||||
|
||||
@@ -114,3 +114,28 @@ func UUIdV4() (string, error) {
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
||||
|
||||
// RandUniqueIntSlice generate a slice of random int of length n that do not repeat.
|
||||
// Play: https://go.dev/play/p/uBkRSOz73Ec
|
||||
func RandUniqueIntSlice(n, min, max int) []int {
|
||||
if min > max {
|
||||
return []int{}
|
||||
}
|
||||
if n > max-min {
|
||||
n = max - min
|
||||
}
|
||||
|
||||
nums := make([]int, n)
|
||||
used := make(map[int]struct{}, n)
|
||||
for i := 0; i < n; {
|
||||
r := RandInt(min, max)
|
||||
if _, use := used[r]; use {
|
||||
continue
|
||||
}
|
||||
used[r] = struct{}{}
|
||||
nums[i] = r
|
||||
i++
|
||||
}
|
||||
|
||||
return nums
|
||||
}
|
||||
|
||||
@@ -123,3 +123,14 @@ func ExampleUUIdV4() {
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleRandUniqueIntSlice() {
|
||||
result := RandUniqueIntSlice(5, 0, 10)
|
||||
|
||||
if len(result) == 5 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
@@ -103,3 +103,36 @@ func TestUUIdV4(t *testing.T) {
|
||||
isUUiDV4 := regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`)
|
||||
assert.Equal(true, isUUiDV4.MatchString(uuid))
|
||||
}
|
||||
|
||||
func TestRandUniqueIntSlice(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRandUniqueIntSlice")
|
||||
|
||||
r1 := RandUniqueIntSlice(5, 0, 9)
|
||||
assert.Equal(len(r1), 5)
|
||||
if hasDuplicate(r1) {
|
||||
t.Error("hasDuplicate int")
|
||||
}
|
||||
|
||||
r2 := RandUniqueIntSlice(20, 0, 10)
|
||||
assert.Equal(len(r2), 10)
|
||||
if hasDuplicate(r2) {
|
||||
t.Error("hasDuplicate int")
|
||||
}
|
||||
|
||||
r3 := RandUniqueIntSlice(10, 20, 10)
|
||||
assert.Equal(len(r3), 0)
|
||||
|
||||
r4 := RandUniqueIntSlice(0, 20, 10)
|
||||
assert.Equal(len(r4), 0)
|
||||
}
|
||||
|
||||
func hasDuplicate(arr []int) bool {
|
||||
elements := make(map[int]bool)
|
||||
for _, v := range arr {
|
||||
if elements[v] {
|
||||
return true
|
||||
}
|
||||
elements[v] = true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -128,42 +128,46 @@ func TestEqualWith(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEvery(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestEvery")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestEvery")
|
||||
assert.Equal(false, Every(nums, isEven))
|
||||
}
|
||||
|
||||
func TestNone(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestNone")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
check := func(i, num int) bool {
|
||||
return num%2 == 1
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestNone")
|
||||
assert.Equal(false, None(nums, check))
|
||||
}
|
||||
|
||||
func TestSome(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSome")
|
||||
|
||||
nums := []int{1, 2, 3, 5}
|
||||
hasEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestSome")
|
||||
assert.Equal(true, Some(nums, hasEven))
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFilter")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestFilter")
|
||||
assert.Equal([]int{2, 4}, Filter(nums, isEven))
|
||||
|
||||
type student struct {
|
||||
@@ -189,17 +193,16 @@ func TestFilter(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGroupBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGroupBy")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
evenFunc := func(i, num int) bool {
|
||||
return (num % 2) == 0
|
||||
}
|
||||
expectedEven := []int{2, 4, 6}
|
||||
expectedOdd := []int{1, 3, 5}
|
||||
even, odd := GroupBy(nums, evenFunc)
|
||||
|
||||
assert := internal.NewAssert(t, "TestGroupBy")
|
||||
assert.Equal(expectedEven, even)
|
||||
assert.Equal(expectedOdd, odd)
|
||||
assert.Equal([]int{2, 4, 6}, even)
|
||||
assert.Equal([]int{1, 3, 5}, odd)
|
||||
}
|
||||
|
||||
func TestGroupWith(t *testing.T) {
|
||||
@@ -240,65 +243,64 @@ func TestFind(t *testing.T) {
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := Find(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
result, ok := Find(nums, even)
|
||||
|
||||
assert := internal.NewAssert(t, "TestFind")
|
||||
assert.Equal(2, *res)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, *result)
|
||||
}
|
||||
|
||||
func TestFindBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFindBy")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := FindBy(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
assert.Equal(2, res)
|
||||
|
||||
res, ok = FindBy(nums, func(_ int, v int) bool {
|
||||
result, ok := FindBy(nums, func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
})
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(2, result)
|
||||
|
||||
result, ok = FindBy(nums, func(_ int, v int) bool {
|
||||
return v == 6
|
||||
})
|
||||
assert.Equal(res == 0 && ok == false, true)
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(0, result)
|
||||
}
|
||||
|
||||
func TestFindLastBy(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFindBy")
|
||||
assert := internal.NewAssert(t, "TestFindLastBy")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := FindLastBy(nums, even)
|
||||
result, ok := FindLastBy(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
assert.Equal(4, res)
|
||||
assert.Equal(4, result)
|
||||
|
||||
res, ok = FindLastBy(nums, func(_ int, v int) bool {
|
||||
result, ok = FindLastBy(nums, func(_ int, v int) bool {
|
||||
return v == 6
|
||||
})
|
||||
assert.Equal(res == 0 && ok == false, true)
|
||||
|
||||
assert.Equal(result == 0 && ok == false, true)
|
||||
}
|
||||
|
||||
func TestFindLast(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFindLast")
|
||||
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
even := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
res, ok := FindLast(nums, even)
|
||||
result, ok := FindLast(nums, even)
|
||||
if !ok {
|
||||
t.Fatal("found nothing")
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestFindLast")
|
||||
assert.Equal(4, *res)
|
||||
assert.Equal(4, *result)
|
||||
}
|
||||
|
||||
func TestFindFoundNothing(t *testing.T) {
|
||||
@@ -307,45 +309,47 @@ func TestFindFoundNothing(t *testing.T) {
|
||||
return num > 1
|
||||
}
|
||||
_, ok := Find(nums, findFunc)
|
||||
// if ok {
|
||||
// t.Fatal("found something")
|
||||
// }
|
||||
|
||||
assert := internal.NewAssert(t, "TestFindFoundNothing")
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFlatten")
|
||||
|
||||
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
expected := [][]string{{"a", "b"}, {"c", "d"}}
|
||||
|
||||
assert := internal.NewAssert(t, "TestFlatten")
|
||||
assert.Equal(expected, Flatten(input))
|
||||
}
|
||||
|
||||
func TestFlattenDeep(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFlattenDeep")
|
||||
|
||||
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
expected := []string{"a", "b", "c", "d"}
|
||||
|
||||
assert := internal.NewAssert(t, "TestFlattenDeep")
|
||||
assert.Equal(expected, FlattenDeep(input))
|
||||
}
|
||||
|
||||
func TestForEach(t *testing.T) {
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
expected := []int{3, 4, 5, 6, 7}
|
||||
assert := internal.NewAssert(t, "TestForEach")
|
||||
|
||||
var numbersAddTwo []int
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
var result []int
|
||||
addTwo := func(index int, value int) {
|
||||
numbersAddTwo = append(numbersAddTwo, value+2)
|
||||
result = append(result, value+2)
|
||||
}
|
||||
|
||||
ForEach(numbers, addTwo)
|
||||
|
||||
assert := internal.NewAssert(t, "TestForEach")
|
||||
assert.Equal(expected, numbersAddTwo)
|
||||
assert.Equal([]int{3, 4, 5, 6, 7}, result)
|
||||
}
|
||||
|
||||
func TestForEachWithBreak(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestForEach")
|
||||
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
var sum int
|
||||
@@ -358,17 +362,17 @@ func TestForEachWithBreak(t *testing.T) {
|
||||
return true
|
||||
})
|
||||
|
||||
assert := internal.NewAssert(t, "TestForEach")
|
||||
assert.Equal(6, sum)
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMap")
|
||||
|
||||
nums := []int{1, 2, 3, 4}
|
||||
multiplyTwo := func(i, num int) int {
|
||||
return num * 2
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestMap")
|
||||
assert.Equal([]int{2, 4, 6, 8}, Map(nums, multiplyTwo))
|
||||
|
||||
type student struct {
|
||||
@@ -424,6 +428,8 @@ func TestFlatMap(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReduce")
|
||||
|
||||
cases := [][]int{
|
||||
{},
|
||||
{1},
|
||||
@@ -435,8 +441,6 @@ func TestReduce(t *testing.T) {
|
||||
return v1 + v2
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestReduce")
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual := Reduce(cases[i], f, 0)
|
||||
assert.Equal(expected[i], actual)
|
||||
@@ -460,7 +464,7 @@ func TestReduceBy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "ReduceRight")
|
||||
assert := internal.NewAssert(t, "TestReduceRight")
|
||||
|
||||
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
|
||||
return agg + fmt.Sprintf("%v", item)
|
||||
@@ -470,26 +474,29 @@ func TestReduceRight(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIntSlice(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIntSlice")
|
||||
|
||||
var nums []any
|
||||
nums = append(nums, 1, 2, 3)
|
||||
|
||||
assert := internal.NewAssert(t, "TestIntSlice")
|
||||
assert.Equal([]int{1, 2, 3}, IntSlice(nums))
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestStringSlice")
|
||||
|
||||
var strs []any
|
||||
strs = append(strs, "a", "b", "c")
|
||||
|
||||
assert := internal.NewAssert(t, "TestStringSlice")
|
||||
assert.Equal([]string{"a", "b", "c"}, StringSlice(strs))
|
||||
}
|
||||
|
||||
func TestInterfaceSlice(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestInterfaceSlice")
|
||||
|
||||
strs := []string{"a", "b", "c"}
|
||||
expect := []any{"a", "b", "c"}
|
||||
|
||||
assert := internal.NewAssert(t, "TestInterfaceSlice")
|
||||
assert.Equal(expect, InterfaceSlice(strs))
|
||||
}
|
||||
|
||||
@@ -657,6 +664,8 @@ func TestMerge(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIntersection(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIntersection")
|
||||
|
||||
s1 := []int{1, 2, 2, 3}
|
||||
s2 := []int{1, 2, 3, 4}
|
||||
s3 := []int{0, 2, 3, 5, 6}
|
||||
@@ -668,17 +677,15 @@ func TestIntersection(t *testing.T) {
|
||||
{1, 2, 3},
|
||||
{},
|
||||
}
|
||||
res := []any{
|
||||
result := []any{
|
||||
Intersection(s1, s2, s3),
|
||||
Intersection(s1, s2),
|
||||
Intersection(s1),
|
||||
Intersection(s1, s4),
|
||||
}
|
||||
|
||||
assert := internal.NewAssert(t, "TestIntersection")
|
||||
|
||||
for i := 0; i < len(res); i++ {
|
||||
assert.Equal(expected[i], res[i])
|
||||
for i := 0; i < len(result); i++ {
|
||||
assert.Equal(expected[i], result[i])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,6 +718,7 @@ func TestDifference(t *testing.T) {
|
||||
|
||||
s1 := []int{1, 2, 3, 4, 5}
|
||||
s2 := []int{4, 5, 6}
|
||||
|
||||
assert.Equal([]int{1, 2, 3}, Difference(s1, s2))
|
||||
}
|
||||
|
||||
@@ -722,6 +730,7 @@ func TestDifferenceWith(t *testing.T) {
|
||||
isDouble := func(v1, v2 int) bool {
|
||||
return v2 == 2*v1
|
||||
}
|
||||
|
||||
assert.Equal([]int{1, 5}, DifferenceWith(s1, s2, isDouble))
|
||||
}
|
||||
|
||||
@@ -733,6 +742,7 @@ func TestDifferenceBy(t *testing.T) {
|
||||
addOne := func(i int, v int) int {
|
||||
return v + 1
|
||||
}
|
||||
|
||||
assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne))
|
||||
}
|
||||
|
||||
@@ -848,7 +858,7 @@ func TestSortByFielDesc(t *testing.T) {
|
||||
err := SortByField(students, "age", "desc")
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(students, studentsOfSortByAge)
|
||||
assert.Equal(studentsOfSortByAge, students)
|
||||
}
|
||||
|
||||
func TestSortByFieldAsc(t *testing.T) {
|
||||
@@ -874,7 +884,7 @@ func TestSortByFieldAsc(t *testing.T) {
|
||||
err := SortByField(students, "age")
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(students, studentsOfSortByAge)
|
||||
assert.Equal(studentsOfSortByAge, students)
|
||||
}
|
||||
|
||||
func TestWithout(t *testing.T) {
|
||||
@@ -886,10 +896,10 @@ func TestWithout(t *testing.T) {
|
||||
func TestShuffle(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestShuffle")
|
||||
|
||||
s := []int{1, 2, 3, 4, 5}
|
||||
res := Shuffle(s)
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
result := Shuffle(numbers)
|
||||
|
||||
assert.Equal(5, len(res))
|
||||
assert.Equal(5, len(result))
|
||||
}
|
||||
|
||||
func TestIndexOf(t *testing.T) {
|
||||
@@ -1000,13 +1010,12 @@ func TestKeyBy(t *testing.T) {
|
||||
return len(str)
|
||||
})
|
||||
|
||||
assert.Equal(result, map[int]string{1: "a", 2: "ab", 3: "abc"})
|
||||
assert.Equal(map[int]string{1: "a", 2: "ab", 3: "abc"}, result)
|
||||
}
|
||||
|
||||
func TestRepeat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRepeat")
|
||||
|
||||
result := Repeat("a", 6)
|
||||
|
||||
assert.Equal(result, []string{"a", "a", "a", "a", "a", "a"})
|
||||
assert.Equal([]string{}, Repeat("a", 0))
|
||||
assert.Equal([]string{"a", "a", "a", "a", "a", "a"}, Repeat("a", 6))
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ func (s stream[T]) FindFirst() (T, bool) {
|
||||
}
|
||||
|
||||
// FindLast returns the last element of this stream and true, or zero value and false if the stream is empty.
|
||||
// Play: https://go.dev/play/p/9xEf0-6C1e3
|
||||
// Play: https://go.dev/play/p/WZD2rDAW-2h
|
||||
func (s stream[T]) FindLast() (T, bool) {
|
||||
var result T
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ package strutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -448,7 +449,7 @@ func IndexOffset(str string, substr string, idxFrom int) int {
|
||||
|
||||
// ReplaceWithMap returns a copy of `str`,
|
||||
// which is replaced by a map in unordered way, case-sensitively.
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/h3t7CNj2Vvu
|
||||
func ReplaceWithMap(str string, replaces map[string]string) string {
|
||||
for k, v := range replaces {
|
||||
str = strings.ReplaceAll(str, k, v)
|
||||
@@ -460,6 +461,7 @@ func ReplaceWithMap(str string, replaces map[string]string) string {
|
||||
// SplitAndTrim splits string `str` by a string `delimiter` to a slice,
|
||||
// and calls Trim to every element of this slice. It ignores the elements
|
||||
// which are empty after Trim.
|
||||
// Play: https://go.dev/play/p/ZNL6o4SkYQ7
|
||||
func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
|
||||
result := make([]string, 0)
|
||||
|
||||
@@ -490,6 +492,7 @@ var (
|
||||
|
||||
// Trim strips whitespace (or other characters) from the beginning and end of a string.
|
||||
// The optional parameter `characterMask` specifies the additional stripped characters.
|
||||
// Play: https://go.dev/play/p/Y0ilP0NRV3j
|
||||
func Trim(str string, characterMask ...string) string {
|
||||
trimChars := DefaultTrimChars
|
||||
|
||||
@@ -499,3 +502,73 @@ func Trim(str string, characterMask ...string) string {
|
||||
|
||||
return strings.Trim(str, trimChars)
|
||||
}
|
||||
|
||||
// HideString hide some chars in source string with param `replaceChar`.
|
||||
// replace range is origin[start : end]. [start, end)
|
||||
// Play: https://go.dev/play/p/pzbaIVCTreZ)
|
||||
func HideString(origin string, start, end int, replaceChar string) string {
|
||||
size := len(origin)
|
||||
|
||||
if start > size-1 || start < 0 || end < 0 || start > end {
|
||||
return origin
|
||||
}
|
||||
|
||||
if end > size {
|
||||
end = size
|
||||
}
|
||||
|
||||
if replaceChar == "" {
|
||||
return origin
|
||||
}
|
||||
|
||||
startStr := origin[0:start]
|
||||
endStr := origin[end:size]
|
||||
|
||||
replaceSize := end - start
|
||||
replaceStr := strings.Repeat(replaceChar, replaceSize)
|
||||
|
||||
return startStr + replaceStr + endStr
|
||||
}
|
||||
|
||||
// ContainsAll return true if target string contains all the substrs.
|
||||
// Play: https://go.dev/play/p/KECtK2Os4zq
|
||||
func ContainsAll(str string, substrs []string) bool {
|
||||
for _, v := range substrs {
|
||||
if !strings.Contains(str, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ContainsAny return true if target string contains any one of the substrs.
|
||||
// Play: https://go.dev/play/p/dZGSSMB3LXE
|
||||
func ContainsAny(str string, substrs []string) bool {
|
||||
for _, v := range substrs {
|
||||
if strings.Contains(str, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
whitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`\s`)
|
||||
mutiWhitespaceRegexMatcher *regexp.Regexp = regexp.MustCompile(`[[:space:]]{2,}|[\s\p{Zs}]{2,}`)
|
||||
)
|
||||
|
||||
// RemoveWhiteSpace remove whitespace characters from a string.
|
||||
// when set repalceAll is true removes all whitespace, false only replaces consecutive whitespace characters with one space.
|
||||
// Play: https://go.dev/play/p/HzLC9vsTwkf
|
||||
func RemoveWhiteSpace(str string, repalceAll bool) string {
|
||||
if repalceAll && str != "" {
|
||||
return strings.Join(strings.Fields(str), "")
|
||||
} else if str != "" {
|
||||
str = mutiWhitespaceRegexMatcher.ReplaceAllString(str, " ")
|
||||
str = whitespaceRegexMatcher.ReplaceAllString(str, " ")
|
||||
}
|
||||
|
||||
return strings.TrimSpace(str)
|
||||
}
|
||||
|
||||
@@ -416,22 +416,19 @@ func ExampleWordCount() {
|
||||
|
||||
result1 := WordCount("a word")
|
||||
result2 := WordCount("I'am a programmer")
|
||||
result3 := WordCount("Bonjour, je suis programmeur")
|
||||
result4 := WordCount("a -b-c' 'd'e")
|
||||
result5 := WordCount("你好,我是一名码农")
|
||||
result6 := WordCount("こんにちは,私はプログラマーです")
|
||||
result3 := WordCount("a -b-c' 'd'e")
|
||||
result4 := WordCount("你好,我是一名码农")
|
||||
result5 := WordCount("こんにちは,私はプログラマーです")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 3
|
||||
// 0
|
||||
// 0
|
||||
@@ -571,3 +568,68 @@ func ExampleSplitAndTrim() {
|
||||
// [a b c d $1]
|
||||
// [a b c d 1]
|
||||
}
|
||||
|
||||
func ExampleHideString() {
|
||||
str := "13242658976"
|
||||
|
||||
result1 := HideString(str, 3, 3, "*")
|
||||
result2 := HideString(str, 3, 4, "*")
|
||||
result3 := HideString(str, 3, 7, "*")
|
||||
result4 := HideString(str, 7, 11, "*")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// 13242658976
|
||||
// 132*2658976
|
||||
// 132****8976
|
||||
// 1324265****
|
||||
}
|
||||
|
||||
func ExampleContainsAll() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := ContainsAll(str, []string{"hello", "world"})
|
||||
result2 := ContainsAll(str, []string{"hello", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleContainsAny() {
|
||||
str := "hello world"
|
||||
|
||||
result1 := ContainsAny(str, []string{"hello", "world"})
|
||||
result2 := ContainsAny(str, []string{"hello", "abc"})
|
||||
result3 := ContainsAny(str, []string{"123", "abc"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleRemoveWhiteSpace() {
|
||||
str := " hello \r\n \t world"
|
||||
|
||||
result1 := RemoveWhiteSpace(str, true)
|
||||
result2 := RemoveWhiteSpace(str, false)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// helloworld
|
||||
// hello world
|
||||
}
|
||||
|
||||
@@ -432,3 +432,47 @@ func TestSplitAndTrim(t *testing.T) {
|
||||
assert.Equal([]string{"a", "b", "c", "d", "$1"}, result1)
|
||||
assert.Equal([]string{"a", "b", "c", "d", "1"}, result2)
|
||||
}
|
||||
|
||||
func TestHideString(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTrim")
|
||||
|
||||
str := "13242658976"
|
||||
|
||||
assert.Equal("13242658976", HideString(str, 0, -1, "*"))
|
||||
assert.Equal("13242658976", HideString(str, 0, 0, "*"))
|
||||
assert.Equal("****2658976", HideString(str, 0, 4, "*"))
|
||||
|
||||
assert.Equal("13242658976", HideString(str, 3, 3, "*"))
|
||||
assert.Equal("132*2658976", HideString(str, 3, 4, "*"))
|
||||
assert.Equal("132****8976", HideString(str, 3, 7, "*"))
|
||||
assert.Equal("1324265****", HideString(str, 7, 11, "*"))
|
||||
|
||||
assert.Equal("1324265****", HideString(str, 7, 100, "*"))
|
||||
assert.Equal("13242658976", HideString(str, 100, 100, "*"))
|
||||
}
|
||||
|
||||
func TestContainsAll(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestContainsAll")
|
||||
|
||||
assert.Equal(true, ContainsAll("hello world", []string{"hello", "world"}))
|
||||
assert.Equal(true, ContainsAll("hello world", []string{""}))
|
||||
assert.Equal(false, ContainsAll("hello world", []string{"hello", "abc"}))
|
||||
}
|
||||
|
||||
func TestContainsAny(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestContainsAny")
|
||||
|
||||
assert.Equal(true, ContainsAny("hello world", []string{"hello", "world"}))
|
||||
assert.Equal(true, ContainsAny("hello world", []string{"hello", "abc"}))
|
||||
assert.Equal(false, ContainsAny("hello world", []string{"123", "abc"}))
|
||||
}
|
||||
|
||||
func TestRemoveWhiteSpace(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRemoveWhiteSpace")
|
||||
|
||||
str := " hello \r\n \t world"
|
||||
|
||||
assert.Equal("", RemoveWhiteSpace("", true))
|
||||
assert.Equal("helloworld", RemoveWhiteSpace(str, true))
|
||||
assert.Equal("hello world", RemoveWhiteSpace(str, false))
|
||||
}
|
||||
|
||||
641
tuple/tuple.go
Normal file
641
tuple/tuple.go
Normal file
@@ -0,0 +1,641 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package tuple implements tuple data type and some operations on it.
|
||||
package tuple
|
||||
|
||||
import "github.com/duke-git/lancet/v2/mathutil"
|
||||
|
||||
// Tuple2 represents a 2 elemnets tuple
|
||||
type Tuple2[A any, B any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple2[A, B]) Unbox() (A, B) {
|
||||
return t.FieldA, t.FieldB
|
||||
}
|
||||
|
||||
// NewTuple2 creates a 2 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple2[A any, B any](a A, b B) Tuple2[A, B] {
|
||||
return Tuple2[A, B]{FieldA: a, FieldB: b}
|
||||
}
|
||||
|
||||
// Zip2 create a slice of Tuple2, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B] {
|
||||
size := mathutil.Max(len(a), len(b))
|
||||
|
||||
tuples := make([]Tuple2[A, B], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
|
||||
tuples[i] = Tuple2[A, B]{FieldA: v1, FieldB: v2}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip2 creates a group of slice from a slice of Tuple2.
|
||||
// Play: todo
|
||||
func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
}
|
||||
|
||||
return r1, r2
|
||||
}
|
||||
|
||||
// Tuple3 represents a 3 elemnets tuple
|
||||
type Tuple3[A any, B any, C any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple3[A, B, C]) Unbox() (A, B, C) {
|
||||
return t.FieldA, t.FieldB, t.FieldC
|
||||
}
|
||||
|
||||
// NewTuple3 creates a 3 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple3[A any, B any, C any](a A, b B, c C) Tuple3[A, B, C] {
|
||||
return Tuple3[A, B, C]{FieldA: a, FieldB: b, FieldC: c}
|
||||
}
|
||||
|
||||
// Zip3 create a slice of Tuple3, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C] {
|
||||
size := mathutil.Max(len(a), len(b), len(c))
|
||||
|
||||
tuples := make([]Tuple3[A, B, C], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
|
||||
tuples[i] = Tuple3[A, B, C]{FieldA: v1, FieldB: v2, FieldC: v3}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip3 creates a group of slice from a slice of Tuple3.
|
||||
// Play: todo
|
||||
func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
}
|
||||
|
||||
return r1, r2, r3
|
||||
}
|
||||
|
||||
// Tuple4 represents a 4 elemnets tuple
|
||||
type Tuple4[A any, B any, C any, D any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple4[A, B, C, D]) Unbox() (A, B, C, D) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD
|
||||
}
|
||||
|
||||
// NewTuple4 creates a 4 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple4[A any, B any, C any, D any](a A, b B, c C, d D) Tuple4[A, B, C, D] {
|
||||
return Tuple4[A, B, C, D]{FieldA: a, FieldB: b, FieldC: c, FieldD: d}
|
||||
}
|
||||
|
||||
// Zip4 create a slice of Tuple4, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, C, D] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d))
|
||||
|
||||
tuples := make([]Tuple4[A, B, C, D], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
v4, _ := getByIndex(d, i)
|
||||
|
||||
tuples[i] = Tuple4[A, B, C, D]{FieldA: v1, FieldB: v2, FieldC: v3, FieldD: v4}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip4 creates a group of slice from a slice of Tuple4.
|
||||
// Play: todo
|
||||
func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, []C, []D) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4
|
||||
}
|
||||
|
||||
// Tuple5 represents a 5 elemnets tuple
|
||||
type Tuple5[A any, B any, C any, D any, E any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple5[A, B, C, D, E]) Unbox() (A, B, C, D, E) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE
|
||||
}
|
||||
|
||||
// NewTuple5 creates a 5 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple5[A any, B any, C any, D any, E any](a A, b B, c C, d D, e E) Tuple5[A, B, C, D, E] {
|
||||
return Tuple5[A, B, C, D, E]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e}
|
||||
}
|
||||
|
||||
// Zip5 create a slice of Tuple5, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) []Tuple5[A, B, C, D, E] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e))
|
||||
|
||||
tuples := make([]Tuple5[A, B, C, D, E], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
v4, _ := getByIndex(d, i)
|
||||
v5, _ := getByIndex(e, i)
|
||||
|
||||
tuples[i] = Tuple5[A, B, C, D, E]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip5 creates a group of slice from a slice of Tuple5.
|
||||
// Play: todo
|
||||
func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ([]A, []B, []C, []D, []E) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5
|
||||
}
|
||||
|
||||
// Tuple6 represents a 6 elemnets tuple
|
||||
type Tuple6[A any, B any, C any, D any, E any, F any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
FieldF F
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple6[A, B, C, D, E, F]) Unbox() (A, B, C, D, E, F) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF
|
||||
}
|
||||
|
||||
// NewTuple6 creates a 6 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple6[A any, B any, C any, D any, E any, F any](a A, b B, c C, d D, e E, f F) Tuple6[A, B, C, D, E, F] {
|
||||
return Tuple6[A, B, C, D, E, F]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f}
|
||||
}
|
||||
|
||||
// Zip6 create a slice of Tuple6, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, e []E, f []F) []Tuple6[A, B, C, D, E, F] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f))
|
||||
|
||||
tuples := make([]Tuple6[A, B, C, D, E, F], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
v4, _ := getByIndex(d, i)
|
||||
v5, _ := getByIndex(e, i)
|
||||
v6, _ := getByIndex(f, i)
|
||||
|
||||
tuples[i] = Tuple6[A, B, C, D, E, F]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5, FieldF: v6}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip6 creates a group of slice from a slice of Tuple6.
|
||||
// Play: todo
|
||||
func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D, E, F]) ([]A, []B, []C, []D, []E, []F) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
r6 := make([]F, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
r6[i] = t.FieldF
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5, r6
|
||||
}
|
||||
|
||||
// Tuple7 represents a 7 elemnets tuple
|
||||
type Tuple7[A any, B any, C any, D any, E any, F any, G any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
FieldF F
|
||||
FieldG G
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple7[A, B, C, D, E, F, G]) Unbox() (A, B, C, D, E, F, G) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG
|
||||
}
|
||||
|
||||
// NewTuple7 creates a 7 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple7[A any, B any, C any, D any, E any, F any, G any](a A, b B, c C, d D, e E, f F, g G) Tuple7[A, B, C, D, E, F, G] {
|
||||
return Tuple7[A, B, C, D, E, F, G]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g}
|
||||
}
|
||||
|
||||
// Zip7 create a slice of Tuple7, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, d []D, e []E, f []F, g []G) []Tuple7[A, B, C, D, E, F, G] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g))
|
||||
|
||||
tuples := make([]Tuple7[A, B, C, D, E, F, G], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
v4, _ := getByIndex(d, i)
|
||||
v5, _ := getByIndex(e, i)
|
||||
v6, _ := getByIndex(f, i)
|
||||
v7, _ := getByIndex(g, i)
|
||||
|
||||
tuples[i] = Tuple7[A, B, C, D, E, F, G]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5, FieldF: v6,
|
||||
FieldG: v7}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip7 creates a group of slice from a slice of Tuple7.
|
||||
// Play: todo
|
||||
func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, B, C, D, E, F, G]) ([]A, []B, []C, []D, []E, []F, []G) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
r6 := make([]F, size)
|
||||
r7 := make([]G, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
r6[i] = t.FieldF
|
||||
r7[i] = t.FieldG
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5, r6, r7
|
||||
}
|
||||
|
||||
// Tuple8 represents a 8 elemnets tuple
|
||||
type Tuple8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
FieldF F
|
||||
FieldG G
|
||||
FieldH H
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple8[A, B, C, D, E, F, G, H]) Unbox() (A, B, C, D, E, F, G, H) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH
|
||||
}
|
||||
|
||||
// NewTuple8 creates a 8 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple8[A any, B any, C any, D any, E any, F any, G any, H any](a A, b B, c C, d D, e E, f F, g G, h H) Tuple8[A, B, C, D, E, F, G, H] {
|
||||
return Tuple8[A, B, C, D, E, F, G, H]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h}
|
||||
}
|
||||
|
||||
// Zip8 create a slice of Tuple8, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H) []Tuple8[A, B, C, D, E, F, G, H] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h))
|
||||
|
||||
tuples := make([]Tuple8[A, B, C, D, E, F, G, H], size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
v1, _ := getByIndex(a, i)
|
||||
v2, _ := getByIndex(b, i)
|
||||
v3, _ := getByIndex(c, i)
|
||||
v4, _ := getByIndex(d, i)
|
||||
v5, _ := getByIndex(e, i)
|
||||
v6, _ := getByIndex(f, i)
|
||||
v7, _ := getByIndex(g, i)
|
||||
v8, _ := getByIndex(h, i)
|
||||
|
||||
tuples[i] = Tuple8[A, B, C, D, E, F, G, H]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5, FieldF: v6,
|
||||
FieldG: v7, FieldH: v8}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip8 creates a group of slice from a slice of Tuple8.
|
||||
// Play: todo
|
||||
func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tuple8[A, B, C, D, E, F, G, H]) ([]A, []B, []C, []D, []E, []F, []G, []H) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
r6 := make([]F, size)
|
||||
r7 := make([]G, size)
|
||||
r8 := make([]H, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
r6[i] = t.FieldF
|
||||
r7[i] = t.FieldG
|
||||
r8[i] = t.FieldH
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5, r6, r7, r8
|
||||
}
|
||||
|
||||
// Tuple9 represents a 9 elemnets tuple
|
||||
type Tuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
FieldF F
|
||||
FieldG G
|
||||
FieldH H
|
||||
FieldI I
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unbox() (A, B, C, D, E, F, G, H, I) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI
|
||||
}
|
||||
|
||||
// NewTuple9 creates a 9 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a A, b B, c C, d D, e E, f F, g G, h H, i I) Tuple9[A, B, C, D, E, F, G, H, I] {
|
||||
return Tuple9[A, B, C, D, E, F, G, H, I]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h, FieldI: i}
|
||||
}
|
||||
|
||||
// Zip9 create a slice of Tuple9, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I) []Tuple9[A, B, C, D, E, F, G, H, I] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i))
|
||||
|
||||
tuples := make([]Tuple9[A, B, C, D, E, F, G, H, I], size)
|
||||
|
||||
for idx := 0; idx < size; idx++ {
|
||||
v1, _ := getByIndex(a, idx)
|
||||
v2, _ := getByIndex(b, idx)
|
||||
v3, _ := getByIndex(c, idx)
|
||||
v4, _ := getByIndex(d, idx)
|
||||
v5, _ := getByIndex(e, idx)
|
||||
v6, _ := getByIndex(f, idx)
|
||||
v7, _ := getByIndex(g, idx)
|
||||
v8, _ := getByIndex(h, idx)
|
||||
v9, _ := getByIndex(i, idx)
|
||||
|
||||
tuples[idx] = Tuple9[A, B, C, D, E, F, G, H, I]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5, FieldF: v6,
|
||||
FieldG: v7, FieldH: v8, FieldI: v9}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip9 creates a group of slice from a slice of Tuple9.
|
||||
// Play: todo
|
||||
func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuples []Tuple9[A, B, C, D, E, F, G, H, I]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
r6 := make([]F, size)
|
||||
r7 := make([]G, size)
|
||||
r8 := make([]H, size)
|
||||
r9 := make([]I, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
r6[i] = t.FieldF
|
||||
r7[i] = t.FieldG
|
||||
r8[i] = t.FieldH
|
||||
r9[i] = t.FieldI
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5, r6, r7, r8, r9
|
||||
}
|
||||
|
||||
// Tuple10 represents a 10 elemnets tuple
|
||||
type Tuple10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any] struct {
|
||||
FieldA A
|
||||
FieldB B
|
||||
FieldC C
|
||||
FieldD D
|
||||
FieldE E
|
||||
FieldF F
|
||||
FieldG G
|
||||
FieldH H
|
||||
FieldI I
|
||||
FieldJ J
|
||||
}
|
||||
|
||||
// Unbox returns values in tuple.
|
||||
// Play: todo
|
||||
func (t Tuple10[A, B, C, D, E, F, G, H, I, J]) Unbox() (A, B, C, D, E, F, G, H, I, J) {
|
||||
return t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI, t.FieldJ
|
||||
}
|
||||
|
||||
// NewTuple10 creates a 10 elemnets tuple from a list of values.
|
||||
// Play: todo
|
||||
func NewTuple10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](a A, b B, c C, d D, e E, f F, g G, h H, i I, j J) Tuple10[A, B, C, D, E, F, G, H, I, J] {
|
||||
return Tuple10[A, B, C, D, E, F, G, H, I, J]{FieldA: a, FieldB: b, FieldC: c, FieldD: d, FieldE: e, FieldF: f, FieldG: g, FieldH: h, FieldI: i, FieldJ: j}
|
||||
}
|
||||
|
||||
// Zip10 create a slice of Tuple10, whose elements are correspond to the given slice elements.
|
||||
// Play: todo
|
||||
func Zip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, j []J) []Tuple10[A, B, C, D, E, F, G, H, I, J] {
|
||||
size := mathutil.Max(len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i), len(j))
|
||||
|
||||
tuples := make([]Tuple10[A, B, C, D, E, F, G, H, I, J], size)
|
||||
|
||||
for idx := 0; idx < size; idx++ {
|
||||
v1, _ := getByIndex(a, idx)
|
||||
v2, _ := getByIndex(b, idx)
|
||||
v3, _ := getByIndex(c, idx)
|
||||
v4, _ := getByIndex(d, idx)
|
||||
v5, _ := getByIndex(e, idx)
|
||||
v6, _ := getByIndex(f, idx)
|
||||
v7, _ := getByIndex(g, idx)
|
||||
v8, _ := getByIndex(h, idx)
|
||||
v9, _ := getByIndex(i, idx)
|
||||
v10, _ := getByIndex(j, idx)
|
||||
|
||||
tuples[idx] = Tuple10[A, B, C, D, E, F, G, H, I, J]{
|
||||
FieldA: v1, FieldB: v2, FieldC: v3,
|
||||
FieldD: v4, FieldE: v5, FieldF: v6,
|
||||
FieldG: v7, FieldH: v8, FieldI: v9,
|
||||
FieldJ: v10}
|
||||
}
|
||||
|
||||
return tuples
|
||||
}
|
||||
|
||||
// Unzip10 creates a group of slice from a slice of Tuple10.
|
||||
// Play: todo
|
||||
func Unzip10[A any, B any, C any, D any, E any, F any, G any, H any, I any, J any](tuples []Tuple10[A, B, C, D, E, F, G, H, I, J]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I, []J) {
|
||||
size := len(tuples)
|
||||
|
||||
r1 := make([]A, size)
|
||||
r2 := make([]B, size)
|
||||
r3 := make([]C, size)
|
||||
r4 := make([]D, size)
|
||||
r5 := make([]E, size)
|
||||
r6 := make([]F, size)
|
||||
r7 := make([]G, size)
|
||||
r8 := make([]H, size)
|
||||
r9 := make([]I, size)
|
||||
r10 := make([]J, size)
|
||||
|
||||
for i, t := range tuples {
|
||||
r1[i] = t.FieldA
|
||||
r2[i] = t.FieldB
|
||||
r3[i] = t.FieldC
|
||||
r4[i] = t.FieldD
|
||||
r5[i] = t.FieldE
|
||||
r6[i] = t.FieldF
|
||||
r7[i] = t.FieldG
|
||||
r8[i] = t.FieldH
|
||||
r9[i] = t.FieldI
|
||||
r10[i] = t.FieldJ
|
||||
}
|
||||
|
||||
return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10
|
||||
}
|
||||
|
||||
func getByIndex[T any](slice []T, index int) (T, bool) {
|
||||
l := len(slice)
|
||||
if index >= l || -index > l {
|
||||
var zeroVal T
|
||||
return zeroVal, false
|
||||
}
|
||||
|
||||
if index >= 0 {
|
||||
return slice[index], true
|
||||
}
|
||||
|
||||
return slice[l+index], true
|
||||
}
|
||||
129
tuple/tuple_example_test.go
Normal file
129
tuple/tuple_example_test.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package tuple implements tuple data type and some operations on it.
|
||||
package tuple
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleNewTuple2() {
|
||||
t := NewTuple2(1, 0.1)
|
||||
fmt.Printf("%v %v", t.FieldA, t.FieldB)
|
||||
// Output: 1 0.1
|
||||
}
|
||||
|
||||
func ExampleTuple2_Unbox() {
|
||||
t := NewTuple2(1, 0.1)
|
||||
v1, v2 := t.Unbox()
|
||||
fmt.Printf("%v %v", v1, v2)
|
||||
// Output: 1 0.1
|
||||
}
|
||||
|
||||
func ExampleNewTuple3() {
|
||||
t := NewTuple3(1, 0.1, "a")
|
||||
fmt.Printf("%v %v %v", t.FieldA, t.FieldB, t.FieldC)
|
||||
// Output: 1 0.1 a
|
||||
}
|
||||
|
||||
func ExampleTuple3_Unbox() {
|
||||
t := NewTuple3(1, 0.1, "a")
|
||||
v1, v2, v3 := t.Unbox()
|
||||
fmt.Printf("%v %v %v", v1, v2, v3)
|
||||
// Output: 1 0.1 a
|
||||
}
|
||||
|
||||
func ExampleNewTuple4() {
|
||||
t := NewTuple4(1, 0.1, "a", true)
|
||||
fmt.Printf("%v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD)
|
||||
// Output: 1 0.1 a true
|
||||
}
|
||||
|
||||
func ExampleTuple4_Unbox() {
|
||||
t := NewTuple4(1, 0.1, "a", true)
|
||||
v1, v2, v3, v4 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v", v1, v2, v3, v4)
|
||||
// Output: 1 0.1 a true
|
||||
}
|
||||
|
||||
func ExampleNewTuple5() {
|
||||
t := NewTuple5(1, 0.1, "a", true, 2)
|
||||
fmt.Printf("%v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE)
|
||||
// Output: 1 0.1 a true 2
|
||||
}
|
||||
|
||||
func ExampleTuple5_Unbox() {
|
||||
t := NewTuple5(1, 0.1, "a", true, 2)
|
||||
v1, v2, v3, v4, v5 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v", v1, v2, v3, v4, v5)
|
||||
// Output: 1 0.1 a true 2
|
||||
}
|
||||
|
||||
func ExampleNewTuple6() {
|
||||
t := NewTuple6(1, 0.1, "a", true, 2, 2.2)
|
||||
fmt.Printf("%v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF)
|
||||
// Output: 1 0.1 a true 2 2.2
|
||||
}
|
||||
|
||||
func ExampleTuple6_Unbox() {
|
||||
t := NewTuple6(1, 0.1, "a", true, 2, 2.2)
|
||||
v1, v2, v3, v4, v5, v6 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v %v", v1, v2, v3, v4, v5, v6)
|
||||
// Output: 1 0.1 a true 2 2.2
|
||||
}
|
||||
|
||||
func ExampleNewTuple7() {
|
||||
t := NewTuple7(1, 0.1, "a", true, 2, 2.2, "b")
|
||||
fmt.Printf("%v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG)
|
||||
// Output: 1 0.1 a true 2 2.2 b
|
||||
}
|
||||
|
||||
func ExampleTuple7_Unbox() {
|
||||
t := NewTuple7(1, 0.1, "a", true, 2, 2.2, "b")
|
||||
v1, v2, v3, v4, v5, v6, v7 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7)
|
||||
// Output: 1 0.1 a true 2 2.2 b
|
||||
}
|
||||
|
||||
func ExampleNewTuple8() {
|
||||
t := NewTuple8(1, 0.1, "a", true, 2, 2.2, "b", "c")
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH)
|
||||
// Output: 1 0.1 a true 2 2.2 b c
|
||||
}
|
||||
|
||||
func ExampleTuple8_Unbox() {
|
||||
t := NewTuple8(1, 0.1, "a", true, 2, 2.2, "b", "c")
|
||||
v1, v2, v3, v4, v5, v6, v7, v8 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8)
|
||||
// Output: 1 0.1 a true 2 2.2 b c
|
||||
}
|
||||
|
||||
func ExampleNewTuple9() {
|
||||
t := NewTuple9(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI)
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1]
|
||||
}
|
||||
|
||||
func ExampleTuple9_Unbox() {
|
||||
t := NewTuple9(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9)
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1]
|
||||
}
|
||||
func ExampleNewTuple10() {
|
||||
type foo struct {
|
||||
A string
|
||||
}
|
||||
t := NewTuple10(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", t.FieldA, t.FieldB, t.FieldC, t.FieldD, t.FieldE, t.FieldF, t.FieldG, t.FieldH, t.FieldI, t.FieldJ)
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1] {a}
|
||||
}
|
||||
|
||||
func ExampleTuple10_Unbox() {
|
||||
type foo struct {
|
||||
A string
|
||||
}
|
||||
t := NewTuple10(1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 := t.Unbox()
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v %v %v", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
|
||||
// Output: 1 0.1 a true 2 2.2 b c map[a:1] {a}
|
||||
}
|
||||
195
tuple/tuple_test.go
Normal file
195
tuple/tuple_test.go
Normal file
@@ -0,0 +1,195 @@
|
||||
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package tuple implements tuple data type and some operations on it.
|
||||
package tuple
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestTuples(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestTuples")
|
||||
|
||||
type foo struct {
|
||||
A string
|
||||
}
|
||||
|
||||
t2 := NewTuple2[int, float64](1, 0.1)
|
||||
t3 := NewTuple3[int, float64, string](1, 0.1, "a")
|
||||
t4 := NewTuple4[int, float64, string, bool](1, 0.1, "a", true)
|
||||
t5 := NewTuple5[int, float64, string, bool, int64](1, 0.1, "a", true, 2)
|
||||
t6 := NewTuple6[int, float64, string, bool, int64, float32](1, 0.1, "a", true, 2, 2.2)
|
||||
t7 := NewTuple7[int, float64, string, bool, int64, float32, string](1, 0.1, "a", true, 2, 2.2, "b")
|
||||
t8 := NewTuple8[int, float64, string, bool, int64, float32, string, string](1, 0.1, "a", true, 2, 2.2, "b", "c")
|
||||
t9 := NewTuple9[int, float64, string, bool, int64, float32, string, string, map[string]int](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
|
||||
t10 := NewTuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
|
||||
|
||||
assert.Equal(t2, Tuple2[int, float64]{FieldA: 1, FieldB: 0.1})
|
||||
assert.Equal(t3, Tuple3[int, float64, string]{FieldA: 1, FieldB: 0.1, FieldC: "a"})
|
||||
assert.Equal(t4, Tuple4[int, float64, string, bool]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true})
|
||||
assert.Equal(t5, Tuple5[int, float64, string, bool, int64]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2})
|
||||
assert.Equal(t6, Tuple6[int, float64, string, bool, int64, float32]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2})
|
||||
assert.Equal(t7, Tuple7[int, float64, string, bool, int64, float32, string]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b"})
|
||||
assert.Equal(t8, Tuple8[int, float64, string, bool, int64, float32, string, string]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c"})
|
||||
assert.Equal(t9, Tuple9[int, float64, string, bool, int64, float32, string, string, map[string]int]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: map[string]int{"a": 1}})
|
||||
assert.Equal(t10, Tuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo]{FieldA: 1, FieldB: 0.1, FieldC: "a", FieldD: true, FieldE: 2, FieldF: 2.2, FieldG: "b", FieldH: "c", FieldI: map[string]int{"a": 1}, FieldJ: foo{A: "a"}})
|
||||
}
|
||||
|
||||
func TestTuple_Unbox(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestTuple_Unbox")
|
||||
|
||||
type foo struct {
|
||||
A string
|
||||
}
|
||||
|
||||
t2 := NewTuple2[int, float64](1, 0.1)
|
||||
v1, v2 := t2.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
|
||||
t3 := NewTuple3[int, float64, string](1, 0.1, "a")
|
||||
v1, v2, v3 := t3.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
|
||||
t4 := NewTuple4[int, float64, string, bool](1, 0.1, "a", true)
|
||||
v1, v2, v3, v4 := t4.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
|
||||
t5 := NewTuple5[int, float64, string, bool, int64](1, 0.1, "a", true, 2)
|
||||
v1, v2, v3, v4, v5 := t5.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
|
||||
t6 := NewTuple6[int, float64, string, bool, int64, float32](1, 0.1, "a", true, 2, 2.2)
|
||||
v1, v2, v3, v4, v5, v6 := t6.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
assert.Equal(float32(2.2), v6)
|
||||
|
||||
t7 := NewTuple7[int, float64, string, bool, int64, float32, string](1, 0.1, "a", true, 2, 2.2, "b")
|
||||
v1, v2, v3, v4, v5, v6, v7 := t7.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
assert.Equal(float32(2.2), v6)
|
||||
assert.Equal("b", v7)
|
||||
|
||||
t8 := NewTuple8[int, float64, string, bool, int64, float32, string, string](1, 0.1, "a", true, 2, 2.2, "b", "c")
|
||||
v1, v2, v3, v4, v5, v6, v7, v8 := t8.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
assert.Equal(float32(2.2), v6)
|
||||
assert.Equal("b", v7)
|
||||
assert.Equal("c", v8)
|
||||
|
||||
t9 := NewTuple9[int, float64, string, bool, int64, float32, string, string, map[string]int](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1})
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9 := t9.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
assert.Equal(float32(2.2), v6)
|
||||
assert.Equal("b", v7)
|
||||
assert.Equal("c", v8)
|
||||
assert.Equal(map[string]int{"a": 1}, v9)
|
||||
|
||||
t10 := NewTuple10[int, float64, string, bool, int64, float32, string, string, map[string]int, foo](1, 0.1, "a", true, 2, 2.2, "b", "c", map[string]int{"a": 1}, foo{A: "a"})
|
||||
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 := t10.Unbox()
|
||||
assert.Equal(1, v1)
|
||||
assert.Equal(0.1, v2)
|
||||
assert.Equal("a", v3)
|
||||
assert.Equal(true, v4)
|
||||
assert.Equal(int64(2), v5)
|
||||
assert.Equal(float32(2.2), v6)
|
||||
assert.Equal("b", v7)
|
||||
assert.Equal("c", v8)
|
||||
assert.Equal(map[string]int{"a": 1}, v9)
|
||||
assert.Equal(foo{A: "a"}, v10)
|
||||
}
|
||||
|
||||
func TestZip(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestZip")
|
||||
|
||||
r2 := Zip2(
|
||||
[]int{1, 2},
|
||||
[]string{"a", "b"},
|
||||
)
|
||||
assert.Equal(r2, []Tuple2[int, string]{
|
||||
{FieldA: 1, FieldB: "a"},
|
||||
{FieldA: 2, FieldB: "b"},
|
||||
})
|
||||
|
||||
r3 := Zip3(
|
||||
[]int{1, 2, 3},
|
||||
[]string{"a", "b", "c"},
|
||||
[]float64{0.1, 0.2, 0.3},
|
||||
)
|
||||
assert.Equal(r3, []Tuple3[int, string, float64]{
|
||||
{FieldA: 1, FieldB: "a", FieldC: 0.1},
|
||||
{FieldA: 2, FieldB: "b", FieldC: 0.2},
|
||||
{FieldA: 3, FieldB: "c", FieldC: 0.3},
|
||||
})
|
||||
|
||||
r4 := Zip4(
|
||||
[]int{1, 2, 3, 4},
|
||||
[]string{"a", "b", "c", "d"},
|
||||
[]float64{0.1, 0.2, 0.3, 0.4},
|
||||
[]bool{true, true, true, true},
|
||||
)
|
||||
assert.Equal(r4, []Tuple4[int, string, float64, bool]{
|
||||
{FieldA: 1, FieldB: "a", FieldC: 0.1, FieldD: true},
|
||||
{FieldA: 2, FieldB: "b", FieldC: 0.2, FieldD: true},
|
||||
{FieldA: 3, FieldB: "c", FieldC: 0.3, FieldD: true},
|
||||
{FieldA: 4, FieldB: "d", FieldC: 0.4, FieldD: true},
|
||||
})
|
||||
|
||||
r5 := Zip5(
|
||||
[]int{1, 2, 3, 4, 5},
|
||||
[]string{"a", "b", "c", "d", "e"},
|
||||
[]float64{0.1, 0.2, 0.3, 0.4, 0.5},
|
||||
[]bool{true, true, true, true, true},
|
||||
[]int{6, 7, 8, 9, 10},
|
||||
)
|
||||
assert.Equal(r5, []Tuple5[int, string, float64, bool, int]{
|
||||
{FieldA: 1, FieldB: "a", FieldC: 0.1, FieldD: true, FieldE: 6},
|
||||
{FieldA: 2, FieldB: "b", FieldC: 0.2, FieldD: true, FieldE: 7},
|
||||
{FieldA: 3, FieldB: "c", FieldC: 0.3, FieldD: true, FieldE: 8},
|
||||
{FieldA: 4, FieldB: "d", FieldC: 0.4, FieldD: true, FieldE: 9},
|
||||
{FieldA: 5, FieldB: "e", FieldC: 0.5, FieldD: true, FieldE: 10},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestUnzip(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := internal.NewAssert(t, "TestUnzip")
|
||||
|
||||
r1, r2, r3 := Unzip3([]Tuple3[string, int, float64]{{FieldA: "a", FieldB: 1, FieldC: 0.1}, {FieldA: "b", FieldB: 2, FieldC: 0.2}})
|
||||
|
||||
assert.Equal(r1, []string{"a", "b"})
|
||||
assert.Equal(r2, []int{1, 2})
|
||||
assert.Equal(r3, []float64{0.1, 0.2})
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
var (
|
||||
alphaMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]+$`)
|
||||
letterRegexMatcher *regexp.Regexp = regexp.MustCompile(`[a-zA-Z]`)
|
||||
numberRegexMatcher *regexp.Regexp = regexp.MustCompile(`\d`)
|
||||
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
|
||||
urlMatcher *regexp.Regexp = regexp.MustCompile(`^((ftp|http|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`)
|
||||
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`)
|
||||
@@ -111,6 +112,11 @@ func ContainLetter(str string) bool {
|
||||
return letterRegexMatcher.MatchString(str)
|
||||
}
|
||||
|
||||
// ContainLetter check if the string contain at least one number.
|
||||
func ContainNumber(input string) bool {
|
||||
return numberRegexMatcher.MatchString(input)
|
||||
}
|
||||
|
||||
// IsJSON checks if the string is valid JSON.
|
||||
// Play: https://go.dev/play/p/8Kip1Itjiil
|
||||
func IsJSON(str string) bool {
|
||||
|
||||
@@ -36,6 +36,24 @@ func ExampleContainLetter() {
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleContainNumber() {
|
||||
result1 := ContainNumber("你好")
|
||||
result2 := ContainNumber("&@#$%^&*")
|
||||
result3 := ContainNumber("ab1")
|
||||
result4 := ContainNumber("1234")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleContainLower() {
|
||||
result1 := ContainLower("abc")
|
||||
result2 := ContainLower("aBC")
|
||||
|
||||
@@ -86,6 +86,23 @@ func TestContainLetter(t *testing.T) {
|
||||
assert.Equal(false, ContainLetter("&@#$%^&*"))
|
||||
}
|
||||
|
||||
func TestContainNumber(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestContainNumber")
|
||||
|
||||
assert.Equal(true, ContainNumber("123"))
|
||||
assert.Equal(true, ContainNumber("1Bc"))
|
||||
assert.Equal(true, ContainNumber("a2c"))
|
||||
assert.Equal(true, ContainNumber("ab3"))
|
||||
assert.Equal(true, ContainNumber("a23"))
|
||||
assert.Equal(true, ContainNumber("a23c"))
|
||||
assert.Equal(true, ContainNumber("1%%%"))
|
||||
|
||||
assert.Equal(false, ContainNumber("ABC"))
|
||||
assert.Equal(false, ContainNumber(""))
|
||||
assert.Equal(false, ContainNumber("你好"))
|
||||
assert.Equal(false, ContainNumber("&@#$%^&*"))
|
||||
}
|
||||
|
||||
func TestIsJSON(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestIsJSON")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user