mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-07 06:02:27 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73fb8fefd2 | ||
|
|
9cf535055d | ||
|
|
8be7b3e396 | ||
|
|
dac706d700 | ||
|
|
2097277a7d | ||
|
|
95b516e278 | ||
|
|
ca373b00a7 | ||
|
|
a220220f09 | ||
|
|
aeef0418a4 | ||
|
|
9b7d8d7abf | ||
|
|
4d21e81263 | ||
|
|
ce2397422e | ||
|
|
4b3a62b36a | ||
|
|
e054680d20 | ||
|
|
5381842eec | ||
|
|
6e0498514c |
16
README.md
16
README.md
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -901,10 +901,17 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
- **<big>HasKey</big>** : checks if map has key or not.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#HasKey)]
|
||||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
||||||
|
- **<big>GetOrSet</big>** : returns value of the given key or set the given value value if not present.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#GetOrSet)]
|
||||||
|
- **<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.
|
- **<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)]
|
[[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.
|
- **<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)]
|
[[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.
|
- **<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)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#NewConcurrentMap)]
|
||||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||||
@@ -1120,7 +1127,7 @@ import "github.com/duke-git/lancet/v2/pointer"
|
|||||||
- **<big>Unwrap</big>** : return the value from the pointer.
|
- **<big>Unwrap</big>** : return the value from the pointer.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/pointer.md#Unwrap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/pointer.md#Unwrap)]
|
||||||
[[play](https://go.dev/play/p/cgeu3g7cjWb)]
|
[[play](https://go.dev/play/p/cgeu3g7cjWb)]
|
||||||
- **<big>UnwarpOr</big>** : UnwarpOr returns the value from the pointer or fallback if the pointer is nil.
|
- **<big>UnwrapOr</big>** : UnwrapOr returns the value from the pointer or fallback if the pointer is nil.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/pointer.md#UnwrapOr)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/pointer.md#UnwrapOr)]
|
||||||
[[play](https://go.dev/play/p/mmNaLC38W8C)]
|
[[play](https://go.dev/play/p/mmNaLC38W8C)]
|
||||||
- **<big>UnwarpOrDefault</big>** : UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
|
- **<big>UnwarpOrDefault</big>** : UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
|
||||||
@@ -1409,6 +1416,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>UniqueBy</big>** : call iteratee func with every item of slice, then remove duplicated.
|
- **<big>UniqueBy</big>** : call iteratee func with every item of slice, then remove duplicated.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueBy)]
|
||||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||||
|
- **<big>UniqueByField</big>** : remove duplicate elements in struct slice by struct field.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#UniqueByField)]
|
||||||
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
- **<big>Union</big>** : creates a slice of unique elements, in order, from all given slices.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Union)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#Union)]
|
||||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||||
@@ -1440,9 +1449,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)]
|
[[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.
|
- **<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)]
|
[[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.
|
- **<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)]
|
[[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>
|
<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>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/duke-git/lancet/releases)
|
[](https://github.com/duke-git/lancet/releases)
|
||||||
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
[](https://pkg.go.dev/github.com/duke-git/lancet/v2)
|
||||||
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
[](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
|
||||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||||
@@ -902,11 +902,18 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
[[play](https://go.dev/play/p/N9qgYg_Ho6f)]
|
||||||
- **<big>HasKey</big>** : 检查 map 是否包含某个 key。
|
- **<big>HasKey</big>** : 检查 map 是否包含某个 key。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#HasKey)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#HasKey)]
|
||||||
|
- **<big>GetOrSet</big>** : 返回给定键的值,如果不存在则设置该值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#GetOrSet)]
|
||||||
[[play](https://go.dev/play/p/isZZHOsDhFc)]
|
[[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对应。
|
- **<big>ToSortedSlicesDefault</big>** : 将map的key和value转化成两个根据key的值从小到大排序的切片,value切片中元素的位置与key对应。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#ToSortedSlicesDefault)]
|
[[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对应。
|
- **<big>ToSortedSlicesWithComparator</big>** : 将map的key和value转化成两个使用比较器函数根据key的值自定义排序规则的切片,value切片中元素的位置与key对应。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#ToSortedSlicesWithComparator)]
|
[[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 结构。
|
- **<big>NewConcurrentMap</big>** : ConcurrentMap 协程安全的 map 结构。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewConcurrentMap)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#NewConcurrentMap)]
|
||||||
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
[[play](https://go.dev/play/p/3PenTPETJT0)]
|
||||||
@@ -1409,6 +1416,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>UniqueBy</big>** : 对切片的每个元素调用 iteratee 函数,然后删除重复元素。
|
- **<big>UniqueBy</big>** : 对切片的每个元素调用 iteratee 函数,然后删除重复元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueBy)]
|
||||||
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
[[play](https://go.dev/play/p/UR323iZLDpv)]
|
||||||
|
- **<big>UniqueByField</big>** : 根据struct字段对struct切片去重复
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#UniqueByField)]
|
||||||
- **<big>Union</big>** : 合并多个切片。
|
- **<big>Union</big>** : 合并多个切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Union)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Union)]
|
||||||
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
[[play](https://go.dev/play/p/hfXV1iRIZOf)]
|
||||||
@@ -1439,8 +1448,11 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Break)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#Break)]
|
||||||
- **<big>RightPadding</big>** : 在切片的右部添加元素。
|
- **<big>RightPadding</big>** : 在切片的右部添加元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#RightPadding)]
|
[[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>** : 在切片的左部添加元素。
|
- **<big>LeftPadding</big>** : 在切片的左部添加元素。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#LeftPadding)]
|
[[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>
|
<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({
|
export const commonConfig = defineConfig({
|
||||||
title: 'Lancet',
|
title: 'Lancet',
|
||||||
appearance: true,
|
appearance: true,
|
||||||
|
ignoreDeadLinks: true,
|
||||||
|
|
||||||
markdown: {
|
markdown: {
|
||||||
theme: {
|
theme: {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import (
|
|||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
- [IsDisjoint](#IsDisjoint)
|
- [IsDisjoint](#IsDisjoint)
|
||||||
- [HasKey](#HasKey)
|
- [HasKey](#HasKey)
|
||||||
|
- [MapToStruct](#MapToStruct)
|
||||||
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
||||||
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
||||||
- [NewConcurrentMap](#NewConcurrentMap)
|
- [NewConcurrentMap](#NewConcurrentMap)
|
||||||
@@ -54,6 +55,8 @@ import (
|
|||||||
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
||||||
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
||||||
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
||||||
|
- [GetOrSet](#GetOrSet)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -948,14 +951,6 @@ func main() {
|
|||||||
|
|
||||||
<p>检查map是否包含某个key。用于代替以下样板代码:</p>
|
<p>检查map是否包含某个key。用于代替以下样板代码:</p>
|
||||||
|
|
||||||
```go
|
|
||||||
_, haskey := amap["baz"];
|
|
||||||
|
|
||||||
if haskey {
|
|
||||||
fmt.Println("map has key baz")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>
|
||||||
|
|
||||||
<p>将map的key和value转化成两个根据key的值从小到大排序的切片,value切片中元素的位置与key对应。</p>
|
<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)
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1012,19 +1050,19 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
m := map[int]string{
|
m := map[int]string{
|
||||||
1: "a",
|
1: "a",
|
||||||
3: "c",
|
3: "c",
|
||||||
2: "b",
|
2: "b",
|
||||||
}
|
}
|
||||||
|
|
||||||
keys, values := ToSortedSlicesDefault(m)
|
keys, values := ToSortedSlicesDefault(m)
|
||||||
|
|
||||||
fmt.Println(keys)
|
fmt.Println(keys)
|
||||||
fmt.Println(values)
|
fmt.Println(values)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [1 2 3]
|
// [1 2 3]
|
||||||
// [a b c]
|
// [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)
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1050,35 +1088,35 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
m1 := map[time.Time]string{
|
m1 := map[time.Time]string{
|
||||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
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, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||||
}
|
}
|
||||||
|
|
||||||
keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
keys1, values1 := maputil.ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||||
return a.Before(b)
|
return a.Before(b)
|
||||||
})
|
})
|
||||||
|
|
||||||
m2 := map[int]string{
|
m2 := map[int]string{
|
||||||
1: "a",
|
1: "a",
|
||||||
3: "c",
|
3: "c",
|
||||||
2: "b",
|
2: "b",
|
||||||
}
|
}
|
||||||
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
keys2, values2 := maputil.ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||||
return a > b
|
return a > b
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println(keys2)
|
fmt.Println(keys2)
|
||||||
fmt.Println(values2)
|
fmt.Println(values2)
|
||||||
|
|
||||||
fmt.Println(keys1)
|
fmt.Println(keys1)
|
||||||
fmt.Println(values1)
|
fmt.Println(values1)
|
||||||
|
|
||||||
// Output:
|
// 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]
|
// [3 2 1]
|
||||||
// [yesterday today tomorrow]
|
// [c b a]
|
||||||
// [3 2 1]
|
// [2024-03-30 00:00:00 +0000 UTC 2024-03-31 00:00:00 +0000 UTC 2024-04-01 00:00:00 +0000 UTC]
|
||||||
// [c b a]
|
// [yesterday today tomorrow]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1144,15 +1182,15 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||||
fmt.Println(val, ok)
|
fmt.Println(val, ok)
|
||||||
wg2.Done()
|
wg2.Done()
|
||||||
}(j)
|
}(j)
|
||||||
}
|
}
|
||||||
wg2.Wait()
|
wg2.Wait()
|
||||||
|
|
||||||
// output: (order may change)
|
// output: (order may change)
|
||||||
// 1 true
|
// 1 true
|
||||||
@@ -1198,15 +1236,15 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||||
fmt.Println(val, ok)
|
fmt.Println(val, ok)
|
||||||
wg2.Done()
|
wg2.Done()
|
||||||
}(j)
|
}(j)
|
||||||
}
|
}
|
||||||
wg2.Wait()
|
wg2.Wait()
|
||||||
|
|
||||||
// output: (order may change)
|
// output: (order may change)
|
||||||
// 1 true
|
// 1 true
|
||||||
@@ -1296,7 +1334,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
cm.Delete(fmt.Sprintf("%d", n))
|
cm.Delete(fmt.Sprintf("%d", n))
|
||||||
@@ -1342,7 +1380,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||||
@@ -1392,7 +1430,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
|
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -25,8 +25,8 @@ import (
|
|||||||
- [Of](#Of)
|
- [Of](#Of)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
- [ExtractPointer](#ExtractPointer)
|
- [ExtractPointer](#ExtractPointer)
|
||||||
- [UnwarpOr](#UnwarpOr)
|
- [UnwrapOr](#UnwrapOr)
|
||||||
- [UnwarpOrDefault](#UnwarpOrDefault)
|
- [UnwrapOrDefault](#UnwrapOrDefault)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -136,14 +136,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="UnwarpOr">UnwarpOr</span>
|
### <span id="UnwrapOr">UnwrapOr</span>
|
||||||
|
|
||||||
<p>返回指针的值,如果指针为零值,则返回fallback。</p>
|
<p>返回指针的值,如果指针为零值,则返回fallback。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
UnwarpOr[T any](p *T, fallback T) T
|
UnwrapOr[T any](p *T, fallback T) T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mmNaLC38W8C)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/mmNaLC38W8C)</span></b>
|
||||||
@@ -163,10 +163,10 @@ func main() {
|
|||||||
var c *int
|
var c *int
|
||||||
var d *string
|
var d *string
|
||||||
|
|
||||||
result1 := pointer.UnwarpOr(&a, 456)
|
result1 := pointer.UnwrapOr(&a, 456)
|
||||||
result2 := pointer.UnwarpOr(&b, "abc")
|
result2 := pointer.UnwrapOr(&b, "abc")
|
||||||
result3 := pointer.UnwarpOr(c, 456)
|
result3 := pointer.UnwrapOr(c, 456)
|
||||||
result4 := pointer.UnwarpOr(d, "def")
|
result4 := pointer.UnwrapOr(d, "def")
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
@@ -181,14 +181,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="UnwarpOrDefault">UnwarpOrDefault</span>
|
### <span id="UnwrapOrDefault">UnwrapOrDefault</span>
|
||||||
|
|
||||||
<p>返回指针的值,如果指针为零值,则返回相应零值。</p>
|
<p>返回指针的值,如果指针为零值,则返回相应零值。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
UnwarpOrDefault[T any](p *T) T
|
UnwrapOrDefault[T any](p *T) T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
|
||||||
@@ -208,10 +208,10 @@ func main() {
|
|||||||
var c *int
|
var c *int
|
||||||
var d *string
|
var d *string
|
||||||
|
|
||||||
result1 := pointer.UnwarpOrDefault(&a)
|
result1 := pointer.UnwrapOrDefault(&a)
|
||||||
result2 := pointer.UnwarpOrDefault(&b)
|
result2 := pointer.UnwrapOrDefault(&b)
|
||||||
result3 := pointer.UnwarpOrDefault(c)
|
result3 := pointer.UnwrapOrDefault(c)
|
||||||
result4 := pointer.UnwarpOrDefault(d)
|
result4 := pointer.UnwrapOrDefault(d)
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ import (
|
|||||||
- [ToSlicePointer](#ToSlicePointer)
|
- [ToSlicePointer](#ToSlicePointer)
|
||||||
- [Unique](#Unique)
|
- [Unique](#Unique)
|
||||||
- [UniqueBy](#UniqueBy)
|
- [UniqueBy](#UniqueBy)
|
||||||
|
- [UniqueByField](#UniqueByField)
|
||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [UnionBy](#UnionBy)
|
- [UnionBy](#UnionBy)
|
||||||
- [UpdateAt](#UpdateAt)
|
- [UpdateAt](#UpdateAt)
|
||||||
@@ -322,12 +323,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Concat">Concat</span>
|
### <span id="Concat">Concat</span>
|
||||||
|
|
||||||
<p>合并多个slices到slice中</p>
|
<p>创建一个新的切片,将传入的切片拼接起来返回。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/gPt-q7zr5mk)</span></b>
|
||||||
@@ -1542,7 +1543,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### <span id="Merge">Merge</span>
|
### <span id="Merge">Merge(废弃:使用Concat)</span>
|
||||||
|
|
||||||
<p>合并多个切片(不会消除重复元素).</p>
|
<p>合并多个切片(不会消除重复元素).</p>
|
||||||
|
|
||||||
@@ -2312,6 +2313,47 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="UniqueByField">UniqueByField</span>
|
||||||
|
|
||||||
|
<p>根据struct字段对struct切片去重复。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func UniqueByField[T any](slice []T, field string) ([]T, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;"></span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := slice.UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [{1 a} {2 b}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>合并多个切片</p>
|
<p>合并多个切片</p>
|
||||||
@@ -2594,14 +2636,14 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
strs := []string{"a", "b", "a", "c", "d", "a"}
|
strs := []string{"a", "b", "a", "c", "d", "a"}
|
||||||
modifiedStrs, count := slice.SetToDefaultIf(strs, func(s string) bool { return "a" == s })
|
modifiedStrs, count := slice.SetToDefaultIf(strs, func(s string) bool { return "a" == s })
|
||||||
|
|
||||||
fmt.Println(modifiedStrs)
|
fmt.Println(modifiedStrs)
|
||||||
fmt.Println(count)
|
fmt.Println(count)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [ b c d ]
|
// [ b c d ]
|
||||||
// 3
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -2615,7 +2657,7 @@ func main() {
|
|||||||
func Break[T any](values []T, predicate func(T) bool) ([]T, []T)
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2648,7 +2690,7 @@ func main() {
|
|||||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2657,11 +2699,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
nums := []int{1, 2, 3, 4, 5}
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
padded := slice.RightPadding(nums, 0, 3)
|
padded := slice.RightPadding(nums, 0, 3)
|
||||||
fmt.Println(padded)
|
fmt.Println(padded)
|
||||||
// Output:
|
// Output:
|
||||||
// [1 2 3 4 5 0 0 0]
|
// [1 2 3 4 5 0 0 0]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -2675,7 +2717,7 @@ func main() {
|
|||||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2684,10 +2726,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
nums := []int{1, 2, 3, 4, 5}
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
padded := slice.LeftPadding(nums, 0, 3)
|
padded := slice.LeftPadding(nums, 0, 3)
|
||||||
fmt.Println(padded)
|
fmt.Println(padded)
|
||||||
// Output:
|
// Output:
|
||||||
// [0 0 0 1 2 3 4 5]
|
// [0 0 0 1 2 3 4 5]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -44,6 +44,7 @@ import (
|
|||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
- [IsDisjoint](#IsDisjoint)
|
- [IsDisjoint](#IsDisjoint)
|
||||||
- [HasKey](#HasKey)
|
- [HasKey](#HasKey)
|
||||||
|
- [MapToStruct](#MapToStruct)
|
||||||
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
- [ToSortedSlicesDefault](#ToSortedSlicesDefault)
|
||||||
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
- [ToSortedSlicesWithComparator](#ToSortedSlicesWithComparator)
|
||||||
- [NewConcurrentMap](#NewConcurrentMap)
|
- [NewConcurrentMap](#NewConcurrentMap)
|
||||||
@@ -54,6 +55,7 @@ import (
|
|||||||
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
- [ConcurrentMap_GetAndDelete](#ConcurrentMap_GetAndDelete)
|
||||||
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
- [ConcurrentMap_Has](#ConcurrentMap_Has)
|
||||||
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
- [ConcurrentMap_Range](#ConcurrentMap_Range)
|
||||||
|
- [GetOrSet](#GetOrSet)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<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>
|
### <span id="ToSortedSlicesDefault">ToSortedSlicesDefault</span>
|
||||||
|
|
||||||
<p>
|
<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)
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1017,19 +1062,19 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
m := map[int]string{
|
m := map[int]string{
|
||||||
1: "a",
|
1: "a",
|
||||||
3: "c",
|
3: "c",
|
||||||
2: "b",
|
2: "b",
|
||||||
}
|
}
|
||||||
|
|
||||||
keys, values := ToSortedSlicesDefault(m)
|
keys, values := maputil.ToSortedSlicesDefault(m)
|
||||||
|
|
||||||
fmt.Println(keys)
|
fmt.Println(keys)
|
||||||
fmt.Println(values)
|
fmt.Println(values)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [1 2 3]
|
// [1 2 3]
|
||||||
// [a b c]
|
// [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)
|
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
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -1057,35 +1102,35 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
m1 := map[time.Time]string{
|
m1 := map[time.Time]string{
|
||||||
time.Date(2024, 3, 31, 0, 0, 0, 0, time.UTC): "today",
|
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, 3, 30, 0, 0, 0, 0, time.UTC): "yesterday",
|
||||||
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC): "tomorrow",
|
||||||
}
|
}
|
||||||
|
|
||||||
keys1, values1 := ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
keys1, values1 := maputil.ToSortedSlicesWithComparator(m1, func(a, b time.Time) bool {
|
||||||
return a.Before(b)
|
return a.Before(b)
|
||||||
})
|
})
|
||||||
|
|
||||||
m2 := map[int]string{
|
m2 := map[int]string{
|
||||||
1: "a",
|
1: "a",
|
||||||
3: "c",
|
3: "c",
|
||||||
2: "b",
|
2: "b",
|
||||||
}
|
}
|
||||||
keys2, values2 := ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
keys2, values2 := maputil.ToSortedSlicesWithComparator(m2, func(a, b int) bool {
|
||||||
return a > b
|
return a > b
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println(keys2)
|
fmt.Println(keys2)
|
||||||
fmt.Println(values2)
|
fmt.Println(values2)
|
||||||
|
|
||||||
fmt.Println(keys1)
|
fmt.Println(keys1)
|
||||||
fmt.Println(values1)
|
fmt.Println(values1)
|
||||||
|
|
||||||
// Output:
|
// 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]
|
// [3 2 1]
|
||||||
// [c b a]
|
// [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
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||||
fmt.Println(val, ok)
|
fmt.Println(val, ok)
|
||||||
wg2.Done()
|
wg2.Done()
|
||||||
}(j)
|
}(j)
|
||||||
}
|
}
|
||||||
wg2.Wait()
|
wg2.Wait()
|
||||||
|
|
||||||
// output: (order may change)
|
// output: (order may change)
|
||||||
// 1 true
|
// 1 true
|
||||||
@@ -1207,15 +1252,15 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
val, ok := cm.Get(fmt.Sprintf("%d", n))
|
||||||
fmt.Println(val, ok)
|
fmt.Println(val, ok)
|
||||||
wg2.Done()
|
wg2.Done()
|
||||||
}(j)
|
}(j)
|
||||||
}
|
}
|
||||||
wg2.Wait()
|
wg2.Wait()
|
||||||
|
|
||||||
// output: (order may change)
|
// output: (order may change)
|
||||||
// 1 true
|
// 1 true
|
||||||
@@ -1305,7 +1350,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
cm.Delete(fmt.Sprintf("%d", n))
|
cm.Delete(fmt.Sprintf("%d", n))
|
||||||
@@ -1352,7 +1397,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
val, ok := cm.GetAndDelete(fmt.Sprintf("%d", n))
|
||||||
@@ -1404,7 +1449,7 @@ func main() {
|
|||||||
wg1.Wait()
|
wg1.Wait()
|
||||||
|
|
||||||
var wg2 sync.WaitGroup
|
var wg2 sync.WaitGroup
|
||||||
wg2.Add(5)
|
wg2.Add(5)
|
||||||
for j := 0; j < 5; j++ {
|
for j := 0; j < 5; j++ {
|
||||||
go func(n int) {
|
go func(n int) {
|
||||||
ok := cm.Has(fmt.Sprintf("%d", n))
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -24,8 +24,8 @@ import (
|
|||||||
|
|
||||||
- [Of](#Of)
|
- [Of](#Of)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
- [UnwarpOr](#UnwarpOr)
|
- [UnwrapOr](#UnwrapOr)
|
||||||
- [UnwarpOrDefault](#UnwarpOrDefault)
|
- [UnwrapOrDefault](#UnwrapOrDefault)
|
||||||
- [ExtractPointer](#ExtractPointer)
|
- [ExtractPointer](#ExtractPointer)
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -103,13 +103,13 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="UnwarpOr">UnwarpOr</span>
|
### <span id="UnwrapOr">UnwrapOr</span>
|
||||||
|
|
||||||
<p>Returns the value from the pointer or fallback if the pointer is nil.</p>
|
<p>Returns the value from the pointer or fallback if the pointer is nil.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
```go
|
```go
|
||||||
UnwarpOr[T any](p *T, fallback T) T
|
UnwrapOr[T any](p *T, fallback T) T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/mmNaLC38W8C)</span></b>
|
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/mmNaLC38W8C)</span></b>
|
||||||
@@ -129,10 +129,10 @@ func main() {
|
|||||||
var c *int
|
var c *int
|
||||||
var d *string
|
var d *string
|
||||||
|
|
||||||
result1 := pointer.UnwarpOr(&a, 456)
|
result1 := pointer.UnwrapOr(&a, 456)
|
||||||
result2 := pointer.UnwarpOr(&b, "abc")
|
result2 := pointer.UnwrapOr(&b, "abc")
|
||||||
result3 := pointer.UnwarpOr(c, 456)
|
result3 := pointer.UnwrapOr(c, 456)
|
||||||
result4 := pointer.UnwarpOr(d, "def")
|
result4 := pointer.UnwrapOr(d, "def")
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
@@ -148,13 +148,13 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="UnwarpOrDefault">UnwarpOrDefault</span>
|
### <span id="UnwrapOrDefault">UnwrapOrDefault</span>
|
||||||
|
|
||||||
<p>Returns the value from the pointer or the default value if the pointer is nil.</p>
|
<p>Returns the value from the pointer or the default value if the pointer is nil.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
```go
|
```go
|
||||||
UnwarpOrDefault[T any](p *T) T
|
UnwrapOrDefault[T any](p *T) T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
|
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ZnGIHf8_o4E)</span></b>
|
||||||
@@ -174,10 +174,10 @@ func main() {
|
|||||||
var c *int
|
var c *int
|
||||||
var d *string
|
var d *string
|
||||||
|
|
||||||
result1 := pointer.UnwarpOrDefault(&a)
|
result1 := pointer.UnwrapOrDefault(&a)
|
||||||
result2 := pointer.UnwarpOrDefault(&b)
|
result2 := pointer.UnwrapOrDefault(&b)
|
||||||
result3 := pointer.UnwarpOrDefault(c)
|
result3 := pointer.UnwrapOrDefault(c)
|
||||||
result4 := pointer.UnwarpOrDefault(d)
|
result4 := pointer.UnwrapOrDefault(d)
|
||||||
|
|
||||||
fmt.Println(result1)
|
fmt.Println(result1)
|
||||||
fmt.Println(result2)
|
fmt.Println(result2)
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ import (
|
|||||||
- [ToSlicePointer](#ToSlicePointer)
|
- [ToSlicePointer](#ToSlicePointer)
|
||||||
- [Unique](#Unique)
|
- [Unique](#Unique)
|
||||||
- [UniqueBy](#UniqueBy)
|
- [UniqueBy](#UniqueBy)
|
||||||
|
- [UniqueByField](#UniqueByField)
|
||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [UnionBy](#UnionBy)
|
- [UnionBy](#UnionBy)
|
||||||
- [UpdateAt](#UpdateAt)
|
- [UpdateAt](#UpdateAt)
|
||||||
@@ -321,12 +322,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Concat">Concat</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/gPt-q7zr5mk)</span></b>
|
||||||
@@ -1540,7 +1541,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>
|
<p>Merge all given slices into one slice.</p>
|
||||||
|
|
||||||
@@ -2310,6 +2311,47 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="UniqueByField">UniqueByField</span>
|
||||||
|
|
||||||
|
<p>Remove duplicate elements in struct slice by struct field.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func UniqueByField[T any](slice []T, field string) ([]T, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;"></span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := slice.UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [{1 a} {2 b}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>Creates a slice of unique values, in order, from all given slices. using == for equality comparisons.</p>
|
<p>Creates a slice of unique values, in order, from all given slices. using == for equality comparisons.</p>
|
||||||
@@ -2612,7 +2654,7 @@ func main() {
|
|||||||
func Break[T any](values []T, predicate func(T) bool) ([]T, []T)
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2645,7 +2687,7 @@ func main() {
|
|||||||
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2655,7 +2697,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
nums := []int{1, 2, 3, 4, 5}
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
padded := RightPadding(nums, 0, 3)
|
padded := slice.RightPadding(nums, 0, 3)
|
||||||
fmt.Println(padded)
|
fmt.Println(padded)
|
||||||
// Output:
|
// Output:
|
||||||
// [1 2 3 4 5 0 0 0]
|
// [1 2 3 4 5 0 0 0]
|
||||||
@@ -2672,7 +2714,7 @@ func main() {
|
|||||||
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T
|
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
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -2682,7 +2724,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
nums := []int{1, 2, 3, 4, 5}
|
nums := []int{1, 2, 3, 4, 5}
|
||||||
padded := LeftPadding(nums, 0, 3)
|
padded := slice.LeftPadding(nums, 0, 3)
|
||||||
fmt.Println(padded)
|
fmt.Println(padded)
|
||||||
// Output:
|
// Output:
|
||||||
// [0 0 0 1 2 3 4 5]
|
// [0 0 0 1 2 3 4 5]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ features:
|
|||||||
details: Well structure, test for every exported function.
|
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;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="">
|
<img style="display: inline-block" src="https://img.shields.io/github/forks/duke-git/lancet?style=social" alt="">
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ features:
|
|||||||
details: 结构良好,测试每个导出的函数。
|
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;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="">
|
<img style="display: inline-block" src="https://img.shields.io/github/forks/duke-git/lancet?style=social" alt="">
|
||||||
</p>
|
</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"
|
"docs:preview": "vitepress preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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.
|
// if dstPath exists, it will return an error.
|
||||||
// Play: https://go.dev/play/p/YAyFTA_UuPb
|
// Play: https://go.dev/play/p/YAyFTA_UuPb
|
||||||
func CopyDir(srcPath string, dstPath string) error {
|
func CopyDir(srcPath string, dstPath string) error {
|
||||||
if !IsDir(srcPath) {
|
srcInfo, err := os.Stat(srcPath)
|
||||||
return errors.New("source path is not a directory")
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
srcPath, err = filepath.Abs(srcPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to get source directory info: %w", err)
|
||||||
}
|
|
||||||
if IsExist(dstPath) {
|
|
||||||
return errors.New("destination path already exists")
|
|
||||||
}
|
|
||||||
dstPath, err = filepath.Abs(dstPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get srcPath's file info
|
if !srcInfo.IsDir() {
|
||||||
srcFileInfo, err := os.Stat(srcPath)
|
return fmt.Errorf("source path is not a directory: %s", srcPath)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create dstPath with srcPath's mode
|
err = os.MkdirAll(dstPath, 0755)
|
||||||
err = os.MkdirAll(dstPath, srcFileInfo.Mode())
|
|
||||||
if err != nil {
|
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 {
|
entries, err := os.ReadDir(srcPath)
|
||||||
if srcPath == path {
|
if err != nil {
|
||||||
return nil
|
return fmt.Errorf("failed to read source directory: %w", err)
|
||||||
}
|
}
|
||||||
curDstPath := filepath.Join(dstPath, filepath.Base(path))
|
|
||||||
if info.IsDir() {
|
for _, entry := range entries {
|
||||||
err = CopyDir(path, curDstPath)
|
srcDir := filepath.Join(srcPath, entry.Name())
|
||||||
|
dstDir := filepath.Join(dstPath, entry.Name())
|
||||||
|
|
||||||
|
if entry.IsDir() {
|
||||||
|
err := CopyDir(srcDir, dstDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = CopyFile(path, curDstPath)
|
err := CopyFile(srcDir, dstDir)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = os.Chmod(curDstPath, info.Mode())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDir checks if the path is directory or not.
|
// 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
|
// MapToStruct converts map to struct
|
||||||
// Play: todo
|
// Play: https://go.dev/play/p/7wYyVfX38Dp
|
||||||
func MapToStruct(m map[string]any, structObj any) error {
|
func MapToStruct(m map[string]any, structObj any) error {
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
err := setStructField(structObj, k, v)
|
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.
|
// 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) {
|
func ToSortedSlicesDefault[K constraints.Ordered, V any](m map[K]V) ([]K, []V) {
|
||||||
keys := make([]K, 0, len(m))
|
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:
|
// 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.
|
// 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) {
|
func ToSortedSlicesWithComparator[K comparable, V any](m map[K]V, comparator func(a, b K) bool) ([]K, []V) {
|
||||||
keys := make([]K, 0, len(m))
|
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
|
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]
|
// [3 2 1]
|
||||||
// [c b a]
|
// [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
|
// HttpClientConfig contains some configurations for http client
|
||||||
type HttpClientConfig struct {
|
type HttpClientConfig struct {
|
||||||
|
Timeout time.Duration
|
||||||
SSLEnabled bool
|
SSLEnabled bool
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
Compressed bool
|
Compressed bool
|
||||||
@@ -113,9 +114,10 @@ type HttpClientConfig struct {
|
|||||||
|
|
||||||
// defaultHttpClientConfig defalut client config.
|
// defaultHttpClientConfig defalut client config.
|
||||||
var defaultHttpClientConfig = &HttpClientConfig{
|
var defaultHttpClientConfig = &HttpClientConfig{
|
||||||
|
Timeout: 50 * time.Second,
|
||||||
Compressed: false,
|
Compressed: false,
|
||||||
HandshakeTimeout: 20 * time.Second,
|
HandshakeTimeout: 10 * time.Second,
|
||||||
ResponseTimeout: 40 * time.Second,
|
ResponseTimeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// HttpClient is used for sending http request.
|
// HttpClient is used for sending http request.
|
||||||
@@ -131,6 +133,7 @@ type HttpClient struct {
|
|||||||
func NewHttpClient() *HttpClient {
|
func NewHttpClient() *HttpClient {
|
||||||
client := &HttpClient{
|
client := &HttpClient{
|
||||||
Client: &http.Client{
|
Client: &http.Client{
|
||||||
|
Timeout: defaultHttpClientConfig.Timeout,
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
|
TLSHandshakeTimeout: defaultHttpClientConfig.HandshakeTimeout,
|
||||||
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
|
ResponseHeaderTimeout: defaultHttpClientConfig.ResponseTimeout,
|
||||||
|
|||||||
@@ -11,17 +11,24 @@ import (
|
|||||||
// Of returns a pointer to the value `v`.
|
// Of returns a pointer to the value `v`.
|
||||||
// Play: https://go.dev/play/p/HFd70x4DrMj
|
// Play: https://go.dev/play/p/HFd70x4DrMj
|
||||||
func Of[T any](v T) *T {
|
func Of[T any](v T) *T {
|
||||||
|
if IsNil(v) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap returns the value from the pointer.
|
// Unwrap returns the value from the pointer.
|
||||||
// Play: https://go.dev/play/p/cgeu3g7cjWb
|
//
|
||||||
|
// Play: https://go.dev/play/p/cgeu3g7cjWb
|
||||||
|
// Deprecated: Please use UnwrapOr
|
||||||
func Unwrap[T any](p *T) T {
|
func Unwrap[T any](p *T) T {
|
||||||
return *p
|
return *p
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnwarpOr returns the value from the pointer or fallback if the pointer is nil.
|
// UnwarpOr returns the value from the pointer or fallback if the pointer is nil.
|
||||||
// Play: https://go.dev/play/p/mmNaLC38W8C
|
//
|
||||||
|
// Play: https://go.dev/play/p/mmNaLC38W8C
|
||||||
|
// Deprecated: Please use UnwrapOr
|
||||||
func UnwarpOr[T any](p *T, fallback T) T {
|
func UnwarpOr[T any](p *T, fallback T) T {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return fallback
|
return fallback
|
||||||
@@ -30,7 +37,9 @@ func UnwarpOr[T any](p *T, fallback T) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
|
// UnwarpOrDefault returns the value from the pointer or the default value if the pointer is nil.
|
||||||
// Play: https://go.dev/play/p/ZnGIHf8_o4E
|
//
|
||||||
|
// Play: https://go.dev/play/p/ZnGIHf8_o4E
|
||||||
|
// Deprecated: Please use UnwrapOr
|
||||||
func UnwarpOrDefault[T any](p *T) T {
|
func UnwarpOrDefault[T any](p *T) T {
|
||||||
var v T
|
var v T
|
||||||
|
|
||||||
@@ -40,9 +49,24 @@ func UnwarpOrDefault[T any](p *T) T {
|
|||||||
return *p
|
return *p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnwrapOr returns the value from the pointer or fallback if the pointer is nil.
|
||||||
|
func UnwrapOr[T any](p *T, fallback ...T) T {
|
||||||
|
if !IsNil(p) {
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
if len(fallback) > 0 {
|
||||||
|
return fallback[0]
|
||||||
|
}
|
||||||
|
var t T
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractPointer returns the underlying value by the given interface type
|
// ExtractPointer returns the underlying value by the given interface type
|
||||||
// Play: https://go.dev/play/p/D7HFjeWU2ZP
|
// Play: https://go.dev/play/p/D7HFjeWU2ZP
|
||||||
func ExtractPointer(value any) any {
|
func ExtractPointer(value any) any {
|
||||||
|
if IsNil(value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
t := reflect.TypeOf(value)
|
t := reflect.TypeOf(value)
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
@@ -56,3 +80,8 @@ func ExtractPointer(value any) any {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNil returns true if the given interface is nil or the underlying value is nil.
|
||||||
|
func IsNil(i interface{}) bool {
|
||||||
|
return i == nil || (reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil())
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,3 +90,61 @@ func ExampleExtractPointer() {
|
|||||||
// Output:
|
// Output:
|
||||||
// 1
|
// 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleIsNil() {
|
||||||
|
a := 1
|
||||||
|
b := &a
|
||||||
|
c := &b
|
||||||
|
d := &c
|
||||||
|
e := &d
|
||||||
|
var f *int
|
||||||
|
|
||||||
|
result1 := IsNil(a)
|
||||||
|
result2 := IsNil(b)
|
||||||
|
result3 := IsNil(c)
|
||||||
|
result4 := IsNil(d)
|
||||||
|
result5 := IsNil(e)
|
||||||
|
result6 := IsNil(f)
|
||||||
|
result7 := IsNil(nil)
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
fmt.Println(result5)
|
||||||
|
fmt.Println(result6)
|
||||||
|
fmt.Println(result7)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleUnwrapOr() {
|
||||||
|
a := 123
|
||||||
|
b := "abc"
|
||||||
|
|
||||||
|
var c *int
|
||||||
|
var d *string
|
||||||
|
|
||||||
|
result1 := UnwrapOr(&a, 456)
|
||||||
|
result2 := UnwrapOr(&b, "efg")
|
||||||
|
result3 := UnwrapOr(c, 456)
|
||||||
|
result4 := UnwrapOr(d, "def")
|
||||||
|
|
||||||
|
fmt.Println(result1)
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(result3)
|
||||||
|
fmt.Println(result4)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 123
|
||||||
|
// abc
|
||||||
|
// 456
|
||||||
|
// def
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ func TestUnwarpOr(t *testing.T) {
|
|||||||
assert.Equal("def", UnwarpOr(d, "def"))
|
assert.Equal("def", UnwarpOr(d, "def"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnwarpOrDefault(t *testing.T) {
|
func TestUnwrapOrDefault(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := internal.NewAssert(t, "TestUnwarpOrDefault")
|
assert := internal.NewAssert(t, "TestUnwrapOrDefault")
|
||||||
|
|
||||||
a := 123
|
a := 123
|
||||||
b := "abc"
|
b := "abc"
|
||||||
|
|||||||
@@ -109,18 +109,18 @@ func Compact[T comparable](slice []T) []T {
|
|||||||
|
|
||||||
// Concat creates a new slice concatenating slice with any additional slices.
|
// Concat creates a new slice concatenating slice with any additional slices.
|
||||||
// Play: https://go.dev/play/p/gPt-q7zr5mk
|
// Play: https://go.dev/play/p/gPt-q7zr5mk
|
||||||
func Concat[T any](slice []T, slices ...[]T) []T {
|
func Concat[T any](slices ...[]T) []T {
|
||||||
totalLen := len(slice)
|
totalLen := 0
|
||||||
|
|
||||||
for _, v := range slices {
|
for _, v := range slices {
|
||||||
totalLen += len(v)
|
totalLen += len(v)
|
||||||
|
if totalLen < 0 {
|
||||||
|
panic("len out of range")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]T, 0, totalLen)
|
result := make([]T, 0, totalLen)
|
||||||
|
|
||||||
result = append(result, slice...)
|
for _, v := range slices {
|
||||||
for _, s := range slices {
|
result = append(result, v...)
|
||||||
result = append(result, s...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -796,6 +796,46 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
|||||||
return Unique(result)
|
return Unique(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UniqueByField remove duplicate elements in struct slice by struct field.
|
||||||
|
// Play: todo
|
||||||
|
func UniqueByField[T any](slice []T, field string) ([]T, error) {
|
||||||
|
seen := map[any]struct{}{}
|
||||||
|
|
||||||
|
var result []T
|
||||||
|
for _, item := range slice {
|
||||||
|
val, err := getField(item, field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get field %s failed: %v", field, err)
|
||||||
|
}
|
||||||
|
if _, ok := seen[val]; !ok {
|
||||||
|
seen[val] = struct{}{}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getField[T any](item T, field string) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(item)
|
||||||
|
t := reflect.TypeOf(item)
|
||||||
|
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
if v.Kind() != reflect.Struct {
|
||||||
|
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", item)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := v.FieldByName(field)
|
||||||
|
if !f.IsValid() {
|
||||||
|
return nil, fmt.Errorf("field name %s not found", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.FieldByName(field).Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Union creates a slice of unique elements, in order, from all given slices.
|
// Union creates a slice of unique elements, in order, from all given slices.
|
||||||
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
||||||
func Union[T comparable](slices ...[]T) []T {
|
func Union[T comparable](slices ...[]T) []T {
|
||||||
@@ -833,20 +873,11 @@ func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: Please use Concat() function instead.
|
||||||
// Merge all given slices into one slice.
|
// Merge all given slices into one slice.
|
||||||
// Play: https://go.dev/play/p/lbjFp784r9N
|
// Play: https://go.dev/play/p/lbjFp784r9N
|
||||||
func Merge[T any](slices ...[]T) []T {
|
func Merge[T any](slices ...[]T) []T {
|
||||||
totalLen := 0
|
return Concat(slices...)
|
||||||
for _, v := range slices {
|
|
||||||
totalLen += len(v)
|
|
||||||
}
|
|
||||||
result := make([]T, 0, totalLen)
|
|
||||||
|
|
||||||
for _, v := range slices {
|
|
||||||
result = append(result, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersection creates a slice of unique elements that included by all slices.
|
// Intersection creates a slice of unique elements that included by all slices.
|
||||||
@@ -1254,7 +1285,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.
|
// 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) {
|
func Break[T any](values []T, predicate func(T) bool) ([]T, []T) {
|
||||||
a := make([]T, 0)
|
a := make([]T, 0)
|
||||||
b := make([]T, 0)
|
b := make([]T, 0)
|
||||||
@@ -1289,7 +1320,7 @@ func Random[T any](slice []T) (val T, idx int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RightPadding adds padding to the right end of a slice.
|
// 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 {
|
func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||||
if paddingLength == 0 {
|
if paddingLength == 0 {
|
||||||
return slice
|
return slice
|
||||||
@@ -1301,7 +1332,7 @@ func RightPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LeftPadding adds padding to the left begin of a slice.
|
// 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 {
|
func LeftPadding[T any](slice []T, paddingValue T, paddingLength int) []T {
|
||||||
if paddingLength == 0 {
|
if paddingLength == 0 {
|
||||||
return slice
|
return slice
|
||||||
|
|||||||
@@ -780,6 +780,28 @@ func ExampleUniqueBy() {
|
|||||||
// [1 2 0]
|
// [1 2 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleUniqueByField() {
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [{1 a} {2 b}]
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleUnion() {
|
func ExampleUnion() {
|
||||||
nums1 := []int{1, 3, 4, 6}
|
nums1 := []int{1, 3, 4, 6}
|
||||||
nums2 := []int{1, 2, 5, 6}
|
nums2 := []int{1, 2, 5, 6}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package slice
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContain(t *testing.T) {
|
func TestContain(t *testing.T) {
|
||||||
@@ -735,6 +736,33 @@ func TestUniqueBy(t *testing.T) {
|
|||||||
assert.Equal([]int{1, 2, 3, 0}, actual)
|
assert.Equal([]int{1, 2, 3, 0}, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUniqueByField(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestUniqueByField")
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueUsers, err := UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal([]User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
}, uniqueUsers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnion(t *testing.T) {
|
func TestUnion(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ func IsIpV4(ipstr string) bool {
|
|||||||
if ip == nil {
|
if ip == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return strings.Contains(ipstr, ".")
|
return ip.To4() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsIpV6 check if the string is a ipv6 address.
|
// IsIpV6 check if the string is a ipv6 address.
|
||||||
@@ -224,7 +224,7 @@ func IsIpV6(ipstr string) bool {
|
|||||||
if ip == nil {
|
if ip == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return strings.Contains(ipstr, ":")
|
return ip.To4() == nil && len(ip) == net.IPv6len
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPort check if the string is a valid net port.
|
// IsPort check if the string is a valid net port.
|
||||||
|
|||||||
Reference in New Issue
Block a user