mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-23 13:52:26 +08:00
Compare commits
10 Commits
v2.3.1
...
ca373b00a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca373b00a7 | ||
|
|
a220220f09 | ||
|
|
aeef0418a4 | ||
|
|
9b7d8d7abf | ||
|
|
4d21e81263 | ||
|
|
ce2397422e | ||
|
|
4b3a62b36a | ||
|
|
e054680d20 | ||
|
|
5381842eec | ||
|
|
6e0498514c |
@@ -901,10 +901,15 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>HasKey</big>** : checks if map has key or not.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#HasKey)]
|
||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
||||
- **<big>MapToStruct</big>** : converts map to struct.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#MapToStruct)]
|
||||
[[play](https://go.dev/play/p/7wYyVfX38Dp)]
|
||||
- **<big>ToSortedSlicesDefault</big>** : converts a map to two slices sorted by key: one for the keys and another for the values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#ToSortedSlicesDefault)]
|
||||
[[play](https://go.dev/play/p/43gEM2po-qy)]
|
||||
- **<big>ToSortedSlicesWithComparator</big>** : converts a map to two slices sorted by key and using a custom comparison function: one for the keys and another for the values.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#ToSortedSlicesWithComparator)]
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewConcurrentMap</big>** : creates a ConcurrentMap with specific shard count.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1440,9 +1445,10 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Break)]
|
||||
- **<big>RightPadding</big>** : adds padding to the right end of a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#RightPadding)]
|
||||
[[play](https://go.dev/play/p/0_2rlLEMBXL)]
|
||||
- **<big>LeftPadding</big>** : adds padding to the left begin of a slice.
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#LeftPadding)]
|
||||
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
|
||||
|
||||
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. <a href="#index">index</a></h3>
|
||||
|
||||
@@ -903,10 +903,15 @@ import "github.com/duke-git/lancet/v2/maputil"
|
||||
- **<big>HasKey</big>** : 检查 map 是否包含某个 key。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#HasKey)]
|
||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
||||
- **<big>MapToStruct</big>** : 将map转成struct。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#MapToStruct)]
|
||||
[[play](https://go.dev/play/p/7wYyVfX38Dp)]
|
||||
- **<big>ToSortedSlicesDefault</big>** : 将map的key和value转化成两个根据key的值从小到大排序的切片,value切片中元素的位置与key对应。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#ToSortedSlicesDefault)]
|
||||
[[play](https://go.dev/play/p/43gEM2po-qy)]
|
||||
- **<big>ToSortedSlicesWithComparator</big>** : 将map的key和value转化成两个使用比较器函数根据key的值自定义排序规则的切片,value切片中元素的位置与key对应。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#ToSortedSlicesWithComparator)]
|
||||
[[play](https://go.dev/play/p/0nlPo6YLdt3)]
|
||||
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewConcurrentMap)]
|
||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||
@@ -1439,8 +1444,11 @@ import "github.com/duke-git/lancet/v2/slice"
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Break)]
|
||||
- **<big>RightPadding</big>** : 在切片的右部添加元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#RightPadding)]
|
||||
[[play](https://go.dev/play/p/0_2rlLEMBXL)]
|
||||
- **<big>LeftPadding</big>** : 在切片的左部添加元素。
|
||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#LeftPadding)]
|
||||
[[play](https://go.dev/play/p/jlQVoelLl2k)]
|
||||
|
||||
|
||||
|
||||
<h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。 <a href="#index">回到目录</a></h3>
|
||||
|
||||
@@ -40,6 +40,7 @@ export const slugify = (str: string): string =>
|
||||
export const commonConfig = defineConfig({
|
||||
title: 'Lancet',
|
||||
appearance: true,
|
||||
ignoreDeadLinks: true,
|
||||
|
||||
markdown: {
|
||||
theme: {
|
||||
|
||||
@@ -44,6 +44,7 @@ import (
|
||||
- [Minus](#Minus)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
- [HasKey](#HasKey)
|
||||
- [MapToStruct](#MapToStruct)
|
||||
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
||||
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
||||
- [NewConcurrentMap](#NewConcurrentMap)
|
||||
@@ -54,6 +55,8 @@ import (
|
||||
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
||||
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
||||
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
||||
- [GetOrSet](#GetOrSet)
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -948,14 +951,6 @@ func main() {
|
||||
|
||||
<p>检查map是否包含某个key。用于代替以下样板代码:</p>
|
||||
|
||||
```go
|
||||
_, haskey := amap["baz"];
|
||||
|
||||
if haskey {
|
||||
fmt.Println("map has key baz")
|
||||
}
|
||||
```
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
@@ -990,6 +985,49 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MapToStruct">MapToStruct</span>
|
||||
|
||||
<p>将map转成struct。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MapToStruct(m map[string]any, structObj any) error
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/7wYyVfX38Dp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
personReqMap := map[string]any{
|
||||
"name": "Nothin",
|
||||
"max_age": 35,
|
||||
"page": 1,
|
||||
"pageSize": 10,
|
||||
}
|
||||
|
||||
type PersonReq struct {
|
||||
Name string `json:"name"`
|
||||
MaxAge int `json:"max_age"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
}
|
||||
var personReq PersonReq
|
||||
_ = maputil.MapToStruct(personReqMap, &personReq)
|
||||
fmt.Println(personReq)
|
||||
|
||||
// Output:
|
||||
// {Nothin 35 1 10}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>
|
||||
|
||||
<p>将map的key和value转化成两个根据key的值从小到大排序的切片,value切片中元素的位置与key对应。</p>
|
||||
@@ -1000,7 +1038,7 @@ func main() {
|
||||
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/43gEM2po-qy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1012,19 +1050,19 @@ import (
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
|
||||
keys, values := ToSortedSlicesDefault(m)
|
||||
keys, values := ToSortedSlicesDefault(m)
|
||||
|
||||
fmt.Println(keys)
|
||||
fmt.Println(values)
|
||||
fmt.Println(keys)
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [a b c]
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [a b c]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1038,7 +1076,7 @@ func main() {
|
||||
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0nlPo6YLdt3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1050,35 +1088,35 @@ import (
|
||||
|
||||
func main() {
|
||||
m1 := map[time.Time]string{
|
||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
||||
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||
}
|
||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
||||
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||
}
|
||||
|
||||
keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||
return a.Before(b)
|
||||
})
|
||||
keys1, values1 := maputil.ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||
return a.Before(b)
|
||||
})
|
||||
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||
return a > b
|
||||
})
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
keys2, values2 := maputil.ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||
return a > b
|
||||
})
|
||||
|
||||
fmt.Println(keys2)
|
||||
fmt.Println(values2)
|
||||
fmt.Println(keys2)
|
||||
fmt.Println(values2)
|
||||
|
||||
fmt.Println(keys1)
|
||||
fmt.Println(values1)
|
||||
fmt.Println(keys1)
|
||||
fmt.Println(values1)
|
||||
|
||||
// Output:
|
||||
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
|
||||
// [yesterday today tomorrow]
|
||||
// [3 2 1]
|
||||
// [c b a]
|
||||
// Output:
|
||||
// [3 2 1]
|
||||
// [c b a]
|
||||
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
|
||||
// [yesterday today tomorrow]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1144,15 +1182,15 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1198,15 +1236,15 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1296,7 +1334,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
cm.Delete(fmt.Sprintf("%d", n))
|
||||
@@ -1342,7 +1380,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||
@@ -1392,7 +1430,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
@@ -1447,3 +1485,41 @@ func main() {
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetOrSet">GetOrSet</span>
|
||||
|
||||
<p>返回给定键的值,如果不存在则设置该值。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;"></span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
}
|
||||
|
||||
result1 := maputil.GetOrSet(m, 1, "1")
|
||||
result2 := maputil.GetOrSet(m, 2, "b")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// b
|
||||
}
|
||||
```
|
||||
@@ -322,12 +322,12 @@ func main() {
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>合并多个slices到slice中</p>
|
||||
<p>创建一个新的切片,将传入的切片拼接起来返回。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](slice []T, slices ...[]T) []T
|
||||
func Concat[T any](slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gPt-q7zr5mk)</span></b>
|
||||
@@ -1542,7 +1542,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
### <span id="Merge">Merge(废弃:使用Concat)</span>
|
||||
|
||||
<p>合并多个切片(不会消除重复元素).</p>
|
||||
|
||||
@@ -2615,7 +2615,7 @@ func main() {
|
||||
func Break[T any](values []T, predicate func(T) bool) ([]T, []T)
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/yLYcBTyeQIz)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2648,7 +2648,7 @@ func main() {
|
||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/0_2rlLEMBXL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2675,7 +2675,7 @@ func main() {
|
||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/jlQVoelLl2k)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
|
||||
@@ -44,6 +44,7 @@ import (
|
||||
- [Minus](#Minus)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
- [HasKey](#HasKey)
|
||||
- [MapToStruct](#MapToStruct)
|
||||
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
||||
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
||||
- [NewConcurrentMap](#NewConcurrentMap)
|
||||
@@ -54,6 +55,7 @@ import (
|
||||
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
||||
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
||||
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
||||
- [GetOrSet](#GetOrSet)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -994,6 +996,49 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="MapToStruct">MapToStruct</span>
|
||||
|
||||
<p>Converts map to struct</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MapToStruct(m map[string]any, structObj any) error
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/7wYyVfX38Dp)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
personReqMap := map[string]any{
|
||||
"name": "Nothin",
|
||||
"max_age": 35,
|
||||
"page": 1,
|
||||
"pageSize": 10,
|
||||
}
|
||||
|
||||
type PersonReq struct {
|
||||
Name string `json:"name"`
|
||||
MaxAge int `json:"max_age"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"pageSize"`
|
||||
}
|
||||
var personReq PersonReq
|
||||
_ = maputil.MapToStruct(personReqMap, &personReq)
|
||||
fmt.Println(personReq)
|
||||
|
||||
// Output:
|
||||
// {Nothin 35 1 10}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>
|
||||
|
||||
<p>
|
||||
@@ -1005,7 +1050,7 @@ Translate the key and value of the map into two slices that are sorted in ascend
|
||||
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](Todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/43gEM2po-qy)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1017,19 +1062,19 @@ import (
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
|
||||
keys, values := ToSortedSlicesDefault(m)
|
||||
keys, values := maputil.ToSortedSlicesDefault(m)
|
||||
|
||||
fmt.Println(keys)
|
||||
fmt.Println(values)
|
||||
fmt.Println(keys)
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [a b c]
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
// [a b c]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1045,7 +1090,7 @@ Translate the key and value of the map into two slices that are sorted according
|
||||
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V)
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](Todo)</span></b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/0nlPo6YLdt3)</span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -1057,35 +1102,35 @@ import (
|
||||
|
||||
func main() {
|
||||
m1 := map[time.Time]string{
|
||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
||||
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||
}
|
||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
||||
time.Date(2024, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||
}
|
||||
|
||||
keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||
return a.Before(b)
|
||||
})
|
||||
keys1, values1 := maputil.ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||
return a.Before(b)
|
||||
})
|
||||
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||
return a > b
|
||||
})
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
3: "c",
|
||||
2: "b",
|
||||
}
|
||||
keys2, values2 := maputil.ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||
return a > b
|
||||
})
|
||||
|
||||
fmt.Println(keys2)
|
||||
fmt.Println(values2)
|
||||
fmt.Println(keys2)
|
||||
fmt.Println(values2)
|
||||
|
||||
fmt.Println(keys1)
|
||||
fmt.Println(values1)
|
||||
fmt.Println(keys1)
|
||||
fmt.Println(values1)
|
||||
|
||||
// Output:
|
||||
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
|
||||
// [yesterday today tomorrow]
|
||||
// Output:
|
||||
// [3 2 1]
|
||||
// [c b a]
|
||||
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
|
||||
// [yesterday today tomorrow]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1152,15 +1197,15 @@ func main() {
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1207,15 +1252,15 @@ func main() {
|
||||
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||
fmt.Println(val, ok)
|
||||
wg2.Done()
|
||||
}(j)
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
// output: (order may change)
|
||||
// 1 true
|
||||
@@ -1305,7 +1350,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
cm.Delete(fmt.Sprintf("%d", n))
|
||||
@@ -1352,7 +1397,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||
@@ -1404,7 +1449,7 @@ func main() {
|
||||
wg1.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
wg2.Add(5)
|
||||
wg2.Add(5)
|
||||
for j := 0; j < 5; j++ {
|
||||
go func(n int) {
|
||||
ok := cm.Has(fmt.Sprintf("%d", n))
|
||||
@@ -1457,3 +1502,40 @@ func main() {
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="GetOrSet">GetOrSet</span>
|
||||
|
||||
<p>Returns value of the given key or set the given value value if not present.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;"></span></b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
}
|
||||
|
||||
result1 := maputil.GetOrSet(m, 1, "1")
|
||||
result2 := maputil.GetOrSet(m, 2, "b")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// b
|
||||
}
|
||||
```
|
||||
@@ -321,12 +321,12 @@ func main() {
|
||||
|
||||
### <span id="Concat">Concat</span>
|
||||
|
||||
<p>Creates a new slice concatenating slice with any additional slices.</p>
|
||||
<p>Concat creates a new slice concatenating slice with any additional slices.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Concat[T any](slice []T, slices ...[]T) []T
|
||||
func Concat[T any](slices ...[]T) []T
|
||||
```
|
||||
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/gPt-q7zr5mk)</span></b>
|
||||
@@ -1540,7 +1540,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
### <span id="Merge">Merge(deprecated: use Concat)</span>
|
||||
|
||||
<p>Merge all given slices into one slice.</p>
|
||||
|
||||
@@ -2612,7 +2612,7 @@ func main() {
|
||||
func Break[T any](values []T, predicate func(T) bool) ([]T, []T)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/yLYcBTyeQIz)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2645,7 +2645,7 @@ func main() {
|
||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/0_2rlLEMBXL)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2655,7 +2655,7 @@ import (
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
padded := RightPadding(nums, 0, 3)
|
||||
padded := slice.RightPadding(nums, 0, 3)
|
||||
fmt.Println(padded)
|
||||
// Output:
|
||||
// [1 2 3 4 5 0 0 0]
|
||||
@@ -2672,7 +2672,7 @@ func main() {
|
||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/jlQVoelLl2k)</span></b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -2682,7 +2682,7 @@ import (
|
||||
|
||||
func main() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
padded := LeftPadding(nums, 0, 3)
|
||||
padded := slice.LeftPadding(nums, 0, 3)
|
||||
fmt.Println(padded)
|
||||
// Output:
|
||||
// [0 0 0 1 2 3 4 5]
|
||||
|
||||
@@ -33,7 +33,7 @@ features:
|
||||
details: Well structure, test for every exported function.
|
||||
---
|
||||
|
||||
<p style="position:relative; top: -316px;left: 560px;">
|
||||
<p style="position:relative; inline-block;top: -330px;left: 30%">
|
||||
<img style="display: inline-block;margin-right:10px;" src="https://img.shields.io/github/stars/duke-git/lancet?style=social" alt="">
|
||||
<img style="display: inline-block" src="https://img.shields.io/github/forks/duke-git/lancet?style=social" alt="">
|
||||
</p>
|
||||
|
||||
@@ -33,7 +33,7 @@ features:
|
||||
details: 结构良好,测试每个导出的函数。
|
||||
---
|
||||
|
||||
<p style="position:relative;display: inline-block;top: -316px;left: 32%">
|
||||
<p style="position:relative;display: inline-block;top: -330px;left: 30%">
|
||||
<img style="display: inline-block;margin-right:10px;" src="https://img.shields.io/github/stars/duke-git/lancet?style=social" alt="">
|
||||
<img style="display: inline-block" src="https://img.shields.io/github/forks/duke-git/lancet?style=social" alt="">
|
||||
</p>
|
||||
|
||||
1171
docs/package-lock.json
generated
1171
docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,6 @@
|
||||
"docs:preview": "vitepress preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.0.0-rc.4"
|
||||
"vitepress": "^1.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,58 +119,43 @@ func CreateDir(absPath string) error {
|
||||
// if dstPath exists, it will return an error.
|
||||
// Play: https://go.dev/play/p/YAyFTA_UuPb
|
||||
func CopyDir(srcPath string, dstPath string) error {
|
||||
if !IsDir(srcPath) {
|
||||
return errors.New("source path is not a directory")
|
||||
}
|
||||
var err error
|
||||
srcPath, err = filepath.Abs(srcPath)
|
||||
srcInfo, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if IsExist(dstPath) {
|
||||
return errors.New("destination path already exists")
|
||||
}
|
||||
dstPath, err = filepath.Abs(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get source directory info: %w", err)
|
||||
}
|
||||
|
||||
// get srcPath's file info
|
||||
srcFileInfo, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
if !srcInfo.IsDir() {
|
||||
return fmt.Errorf("source path is not a directory: %s", srcPath)
|
||||
}
|
||||
|
||||
// create dstPath with srcPath's mode
|
||||
err = os.MkdirAll(dstPath, srcFileInfo.Mode())
|
||||
err = os.MkdirAll(dstPath, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
err = filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error {
|
||||
if srcPath == path {
|
||||
return nil
|
||||
}
|
||||
curDstPath := filepath.Join(dstPath, filepath.Base(path))
|
||||
if info.IsDir() {
|
||||
err = CopyDir(path, curDstPath)
|
||||
entries, err := os.ReadDir(srcPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read source directory: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcDir := filepath.Join(srcPath, entry.Name())
|
||||
dstDir := filepath.Join(dstPath, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
err := CopyDir(srcDir, dstDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = CopyFile(path, curDstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chmod(curDstPath, info.Mode())
|
||||
err := CopyFile(srcDir, dstDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsDir checks if the path is directory or not.
|
||||
|
||||
@@ -310,7 +310,7 @@ func HasKey[K comparable, V any](m map[K]V, key K) bool {
|
||||
}
|
||||
|
||||
// MapToStruct converts map to struct
|
||||
// Play: todo
|
||||
// Play: https://go.dev/play/p/7wYyVfX38Dp
|
||||
func MapToStruct(m map[string]any, structObj any) error {
|
||||
for k, v := range m {
|
||||
err := setStructField(structObj, k, v)
|
||||
@@ -389,6 +389,7 @@ func getFieldNameByJsonTag(structObj any, jsonTag string) string {
|
||||
}
|
||||
|
||||
// ToSortedSlicesDefault converts a map to two slices sorted by key: one for the keys and another for the values.
|
||||
// Play: https://go.dev/play/p/43gEM2po-qy
|
||||
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V) {
|
||||
keys := make([]K, 0, len(m))
|
||||
|
||||
@@ -413,6 +414,7 @@ func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V) {
|
||||
|
||||
// ToSortedSlicesWithComparator converts a map to two slices sorted by key and using a custom comparison function:
|
||||
// one for the keys and another for the values.
|
||||
// Play: https://go.dev/play/p/0nlPo6YLdt3
|
||||
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V) {
|
||||
keys := make([]K, 0, len(m))
|
||||
|
||||
@@ -434,3 +436,15 @@ func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator fun
|
||||
|
||||
return keys, sortedValues
|
||||
}
|
||||
|
||||
// GetOrSet returns value of the given key or set the given value value if not present.
|
||||
// Play: todo
|
||||
func GetOrSet[K comparable, V any](m map[K]V, key K, value V) V {
|
||||
if v, ok := m[key]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
m[key] = value
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -524,3 +524,19 @@ func ExampleToSortedSlicesWithComparator() {
|
||||
// [3 2 1]
|
||||
// [c b a]
|
||||
}
|
||||
|
||||
func ExampleGetOrSet() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
}
|
||||
|
||||
result1 := GetOrSet(m, 1, "1")
|
||||
result2 := GetOrSet(m, 2, "b")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// b
|
||||
}
|
||||
|
||||
@@ -691,3 +691,19 @@ func TestToSortedSlicesWithComparator(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := internal.NewAssert(t, "TestGetOrSet")
|
||||
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
}
|
||||
|
||||
result1 := GetOrSet(m, 1, "1")
|
||||
result2 := GetOrSet(m, 2, "b")
|
||||
|
||||
assert.Equal("a", result1)
|
||||
assert.Equal("b", result2)
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@ type HttpRequest struct {
|
||||
|
||||
// HttpClientConfig contains some configurations for http client
|
||||
type HttpClientConfig struct {
|
||||
Timeout time.Duration
|
||||
SSLEnabled bool
|
||||
TLSConfig *tls.Config
|
||||
Compressed bool
|
||||
@@ -113,9 +114,10 @@ type HttpClientConfig struct {
|
||||
|
||||
// defaultHttpClientConfig defalut client config.
|
||||
var defaultHttpClientConfig = &HttpClientConfig{
|
||||
Timeout: 50 * time.Second,
|
||||
Compressed: false,
|
||||
HandshakeTimeout: 20 * time.Second,
|
||||
ResponseTimeout: 40 * time.Second,
|
||||
HandshakeTimeout: 10 * time.Second,
|
||||
ResponseTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// HttpClient is used for sending http request.
|
||||
@@ -131,6 +133,7 @@ type HttpClient struct {
|
||||
func NewHttpClient() *HttpClient {
|
||||
client := &HttpClient{
|
||||
Client: &http.Client{
|
||||
Timeout: defaultHttpClientConfig.Timeout,
|
||||
Transport: &http.Transport{
|
||||
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
|
||||
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
|
||||
|
||||
@@ -109,18 +109,18 @@ func Compact[T comparable](slice []T) []T {
|
||||
|
||||
// Concat creates a new slice concatenating slice with any additional slices.
|
||||
// Play: https://go.dev/play/p/gPt-q7zr5mk
|
||||
func Concat[T any](slice []T, slices ...[]T) []T {
|
||||
totalLen := len(slice)
|
||||
|
||||
func Concat[T any](slices ...[]T) []T {
|
||||
totalLen := 0
|
||||
for _, v := range slices {
|
||||
totalLen += len(v)
|
||||
if totalLen < 0 {
|
||||
panic("len out of range")
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]T, 0, totalLen)
|
||||
|
||||
result = append(result, slice...)
|
||||
for _, s := range slices {
|
||||
result = append(result, s...)
|
||||
for _, v := range slices {
|
||||
result = append(result, v...)
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -833,20 +833,11 @@ func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Deprecated: Please use Concat() function instead.
|
||||
// Merge all given slices into one slice.
|
||||
// Play: https://go.dev/play/p/lbjFp784r9N
|
||||
func Merge[T any](slices ...[]T) []T {
|
||||
totalLen := 0
|
||||
for _, v := range slices {
|
||||
totalLen += len(v)
|
||||
}
|
||||
result := make([]T, 0, totalLen)
|
||||
|
||||
for _, v := range slices {
|
||||
result = append(result, v...)
|
||||
}
|
||||
|
||||
return result
|
||||
return Concat(slices...)
|
||||
}
|
||||
|
||||
// Intersection creates a slice of unique elements that included by all slices.
|
||||
@@ -1254,7 +1245,7 @@ func Partition[T any](slice []T, predicates ...func(item T) bool) [][]T {
|
||||
}
|
||||
|
||||
// Breaks a list into two parts at the point where the predicate for the first time is true.
|
||||
// Play: Todo
|
||||
// Play: https://go.dev/play/p/yLYcBTyeQIz
|
||||
func Break[T any](values []T, predicate func(T) bool) ([]T, []T) {
|
||||
a := make([]T, 0)
|
||||
b := make([]T, 0)
|
||||
@@ -1289,7 +1280,7 @@ func Random[T any](slice []T) (val T, idx int) {
|
||||
}
|
||||
|
||||
// RightPadding adds padding to the right end of a slice.
|
||||
// Play: Todo
|
||||
// Play: https://go.dev/play/p/0_2rlLEMBXL
|
||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||
if paddingLength == 0 {
|
||||
return slice
|
||||
@@ -1301,7 +1292,7 @@ func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||
}
|
||||
|
||||
// LeftPadding adds padding to the left begin of a slice.
|
||||
// Play: Todo
|
||||
// Play: https://go.dev/play/p/jlQVoelLl2k
|
||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||
if paddingLength == 0 {
|
||||
return slice
|
||||
|
||||
@@ -214,7 +214,7 @@ func IsIpV4(ipstr string) bool {
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(ipstr, ".")
|
||||
return ip.To4() != nil
|
||||
}
|
||||
|
||||
// IsIpV6 check if the string is a ipv6 address.
|
||||
@@ -224,7 +224,7 @@ func IsIpV6(ipstr string) bool {
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(ipstr, ":")
|
||||
return ip.To4() == nil && len(ip) == net.IPv6len
|
||||
}
|
||||
|
||||
// IsPort check if the string is a valid net port.
|
||||
|
||||
Reference in New Issue
Block a user