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

Compare commits

..

16 Commits

Author SHA1 Message Date
dudaodong
73fb8fefd2 release v2.3.2 2024-07-18 10:52:54 +08:00
dudaodong
9cf535055d doc: update readme file 2024-07-18 10:50:29 +08:00
dudaodong
8be7b3e396 rename UnwrapOr 2024-07-18 10:12:16 +08:00
梧桐
dac706d700 🐛 Fixing a bug. about pointer package function (#230)
update:
1. UnwarpOr
2. UnwarpOrDefault
3. ExtractPointer

add:
1. UnwrapOr
2. IsNil
2024-07-18 10:05:07 +08:00
dudaodong
2097277a7d doc: add doc for UniqueByField 2024-06-25 15:20:03 +08:00
dudaodong
95b516e278 feat: add UniqueByField 2024-06-24 19:36:02 +08:00
dudaodong
ca373b00a7 feat: add GetOrSet 2024-06-24 17:29:12 +08:00
dudaodong
a220220f09 feat: add GetOrSet 2024-06-24 17:28:51 +08:00
dudaodong
aeef0418a4 fix: fix bug of CopyDir 2024-06-24 17:09:31 +08:00
dudaodong
9b7d8d7abf doc: update vitepress version 2024-06-11 10:06:33 +08:00
dudaodong
4d21e81263 feat: add Timeout config for http client 2024-06-04 16:28:00 +08:00
残念
ce2397422e perf(slice): make a clearer panic description (#223) 2024-05-30 16:55:30 +08:00
Cannian
4b3a62b36a perf(validator): check Ipv4、Ipv6 by more graceful method (#220) 2024-05-25 08:58:33 +08:00
dudaodong
e054680d20 doc: ignoreDeadLinks in doc 2024-05-14 11:42:48 +08:00
dudaodong
5381842eec doc: update doc for v2.3.1 2024-05-14 11:26:14 +08:00
dudaodong
6e0498514c doc: update doc for v2.3.1 2024-05-14 11:25:01 +08:00
25 changed files with 1468 additions and 650 deletions

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.3.1-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.3.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -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. &nbsp; &nbsp; &nbsp; &nbsp;<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. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>

View File

@@ -4,7 +4,7 @@
<br/> <br/>
![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf) ![Go version](https://img.shields.io/badge/go-%3E%3Dv1.18-9cf)
[![Release](https://img.shields.io/badge/release-2.3.1-green.svg)](https://github.com/duke-git/lancet/releases) [![Release](https://img.shields.io/badge/release-2.3.2-green.svg)](https://github.com/duke-git/lancet/releases)
[![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2) [![GoDoc](https://godoc.org/github.com/duke-git/lancet/v2?status.svg)](https://pkg.go.dev/github.com/duke-git/lancet/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/duke-git/lancet/v2)](https://goreportcard.com/report/github.com/duke-git/lancet/v2)
[![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml) [![test](https://github.com/duke-git/lancet/actions/workflows/codecov.yml/badge.svg?branch=main&event=push)](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
@@ -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 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3> <h3 id="stream"> 19. stream 流,该包仅验证简单的 stream 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>

View File

@@ -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: {

View File

@@ -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
}
```

View File

@@ -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)

View File

@@ -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]
} }
``` ```

View File

@@ -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
}
```

View File

@@ -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)

View File

@@ -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]

View File

@@ -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>

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,6 @@
"docs:preview": "vitepress preview" "docs:preview": "vitepress preview"
}, },
"devDependencies": { "devDependencies": {
"vitepress": "^1.0.0-rc.4" "vitepress": "^1.2.3"
} }
} }

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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())
}

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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}

View File

@@ -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()

View File

@@ -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.