mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
20 Commits
47dccd63af
...
v2.1.17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0aa41f337d | ||
|
|
48814a720a | ||
|
|
04b79b3dfe | ||
|
|
302007ebdf | ||
|
|
965e5fbcda | ||
|
|
70d0adde42 | ||
|
|
0b80074bb7 | ||
|
|
90945a0399 | ||
|
|
4ae7e59829 | ||
|
|
8f0c60cade | ||
|
|
3f6aef1432 | ||
|
|
a714e04470 | ||
|
|
7456621153 | ||
|
|
73ac9825e9 | ||
|
|
930bb9c839 | ||
|
|
3d8f1be212 | ||
|
|
13a4ed59fa | ||
|
|
c799d10ce9 | ||
|
|
5ab322ade2 | ||
|
|
d0ffc61842 |
48
README.md
48
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)
|
||||||
@@ -703,6 +703,10 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
- **<big>TruncRound</big>** : round off n decimal places for int64.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>Range</big>** : Creates a slice of numbers from start with specified count, element step is 1.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
|
||||||
|
- **<big>RangeWithStep</big>** : Creates a slice of numbers from start to end with specified step.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#Range)]
|
||||||
|
|
||||||
### 13. Netutil package contains functions to get net information and send http request.
|
### 13. Netutil package contains functions to get net information and send http request.
|
||||||
|
|
||||||
@@ -916,6 +920,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
- **<big>ForEach</big>** : iterates over elements of slice and invokes function for each element.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
|
- **<big>ForEachWithBreak</big>** : iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ForEach)]
|
||||||
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
- **<big>GroupBy</big>** : iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#GroupBy)]
|
||||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||||
@@ -1022,7 +1028,41 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#KeyBy)]
|
||||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||||
|
|
||||||
### 17. Strutil package contains some functions to manipulate string.
|
|
||||||
|
### 17. Structs package provides several high level functions to manipulate struct, tag, and field.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/structs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- **<big>New</big>** : creates a `Struct` instance.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#New)]
|
||||||
|
- **<big>ToMap</big>** : converts a valid struct to a map.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#ToMap)]
|
||||||
|
- **<big>Fields</big>** : get all fields of a given struct, that the fields are abstract struct field.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#Fields)]
|
||||||
|
- **<big>IsStruct</big>** : check if the struct is valid.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct.md#IsStruct)]
|
||||||
|
- **<big>Tag</big>** : get a `Tag` of the `Field`, `Tag` is a abstract struct field tag
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Tag)]
|
||||||
|
- **<big>Name</big>** : get the field name.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Name)]
|
||||||
|
- **<big>Value</big>** : get the `Field` underlying value.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Value)]
|
||||||
|
- **<big>Kind</big>** : get the field's kind
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#Kind)]
|
||||||
|
- **<big>IsEmbedded</big>** : check if the field is an embedded field.
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsEmbedded)]
|
||||||
|
- **<big>IsExported</big>** : check if the field is exporte
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsExported)]
|
||||||
|
- **<big>IsZero</big>** : check if the field is zero value
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsZero)]
|
||||||
|
- **<big>IsSlice</big>** : check if the field is a slice
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field.md#IsSlice)]
|
||||||
|
|
||||||
|
### 18. Strutil package contains some functions to manipulate string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -1135,7 +1175,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system.md#GetOsBits)]
|
||||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||||
|
|
||||||
### 19. Validator package contains some functions for data validation.
|
### 20. Validator package contains some functions for data validation.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -1228,7 +1268,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsGBK)]
|
||||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||||
|
|
||||||
### 20. xerror package implements helpers for errors.
|
### 21. xerror package implements helpers for errors.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -702,6 +702,10 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
- **<big>TruncRound</big>** : 截短 n 位小数(不进行四舍五入)。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)]
|
||||||
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
[[play](https://go.dev/play/p/aumarSHIGzP)]
|
||||||
|
- **<big>Range</big>** : 根据指定的起始值和数量,创建一个数字切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#Range)]
|
||||||
|
- **<big>RangeWithStep</big>** : 根据指定的起始值,结束值,步长,创建一个数字切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RangeWithStep)]
|
||||||
|
|
||||||
### 13. netutil网络包支持获取 ip 地址,发送 http 请求。
|
### 13. netutil网络包支持获取 ip 地址,发送 http 请求。
|
||||||
|
|
||||||
@@ -915,6 +919,8 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
- **<big>ForEach</big>** : 遍历切片的元素并为每个元素调用 iteratee 函数。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEach)]
|
||||||
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
[[play](https://go.dev/play/p/DrPaa4YsHRF)]
|
||||||
|
- **<big>ForEachWithBreak</big>** : 遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ForEachWithBreak)]
|
||||||
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
- **<big>GroupBy</big>** : 迭代切片的元素,每个元素将按条件分组,返回两个切片。
|
||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#GroupBy)]
|
||||||
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
[[play](https://go.dev/play/p/QVkPxzPR0iA)]
|
||||||
@@ -1021,7 +1027,42 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)]
|
||||||
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
[[play](https://go.dev/play/p/uXod2LWD1Kg)]
|
||||||
|
|
||||||
### 17. strutil 包含字符串处理的相关函数。
|
### 17. structs提供操作struct, tag, field的相关函数。
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/duke-git/lancet/v2/structs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Function list:
|
||||||
|
|
||||||
|
- **<big>New</big>** : `Struct`结构体的构造函数。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#New)]
|
||||||
|
- **<big>ToMap</big>** : 将一个合法的struct对象转换为map[string]any。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#ToMap)]
|
||||||
|
- **<big>Fields</big>** : 获取一个struct对象的属性列表。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||||
|
- **<big>Field</big>** : 根据属性名获取一个struct对象的属性。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#Fields)]
|
||||||
|
- **<big>IsStruct</big>** : 判断是否为一个合法的struct对象。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/struct_zh-CN.md#IsStruct)]
|
||||||
|
- **<big>Tag</big>** : 获取`Field`的`Tag`,默认的tag key是json。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Tag)]
|
||||||
|
- **<big>Name</big>** : 获取属性名。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Name)]
|
||||||
|
- **<big>Value</big>** : 获取`Field`属性的值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Value)]
|
||||||
|
- **<big>Kind</big>** : 获取属性Kind。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#Kind)]
|
||||||
|
- **<big>IsEmbedded</big>** : 判断属性是否为嵌入。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsEmbedded)]
|
||||||
|
- **<big>IsExported</big>** : 判断属性是否导出。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsExported)]
|
||||||
|
- **<big>IsZero</big>** : 判断属性是否为零值。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsZero)]
|
||||||
|
- **<big>IsSlice</big>** : 判断属性是否是切片。
|
||||||
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/structs/field_zh-CN.md#IsSlice)]
|
||||||
|
|
||||||
|
### 18. strutil包含字符串处理的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -1100,7 +1141,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
[[play](https://go.dev/play/p/bj7_odx3vRf)]
|
||||||
|
|
||||||
|
|
||||||
### 18. system 包含 os, runtime, shell command 的相关函数。
|
### 19. system包含 os, runtime, shell command 的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/system"
|
import "github.com/duke-git/lancet/v2/system"
|
||||||
@@ -1136,7 +1177,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN#GetOsBits)]
|
||||||
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
[[play](https://go.dev/play/p/ml-_XH3gJbW)]
|
||||||
|
|
||||||
### 19. validator 验证器包,包含常用字符串格式验证函数。
|
### 20. validator验证器包,包含常用字符串格式验证函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -1229,7 +1270,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)]
|
||||||
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
[[play](https://go.dev/play/p/E2nt3unlmzP)]
|
||||||
|
|
||||||
### 20. xerror 包实现一些错误处理函数
|
### 21. xerror包实现一些错误处理函数
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
|
|||||||
279
async/promise.go
Normal file
279
async/promise.go
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
// Copyright 2023 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package async contain some featurese to support async programming. eg, promise, asycn/await, eventbus.
|
||||||
|
package async
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
|
||||||
|
// ref : chebyrash/promise (https://github.com/chebyrash/promise)
|
||||||
|
// see js promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||||
|
type Promise[T any] struct {
|
||||||
|
runnable func(resolve func(T), reject func(error))
|
||||||
|
result T
|
||||||
|
err error
|
||||||
|
|
||||||
|
pending bool
|
||||||
|
|
||||||
|
mu *sync.Mutex
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// New create a new promise instance.
|
||||||
|
func New[T any](runnable func(resolve func(T), reject func(error))) *Promise[T] {
|
||||||
|
if runnable == nil {
|
||||||
|
panic("runnable function should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &Promise[T]{
|
||||||
|
runnable: runnable,
|
||||||
|
pending: true,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
|
||||||
|
defer p.run()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) run() {
|
||||||
|
p.wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
p.reject(errors.New(fmt.Sprint(err)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
p.runnable(p.resolve, p.reject)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve returns a Promise that has been resolved with a given value.
|
||||||
|
func Resolve[T any](resolution T) *Promise[T] {
|
||||||
|
return &Promise[T]{
|
||||||
|
result: resolution,
|
||||||
|
pending: false,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) resolve(value T) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.result = value
|
||||||
|
p.pending = false
|
||||||
|
|
||||||
|
p.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject returns a Promise that has been rejected with a given error.
|
||||||
|
func Reject[T any](err error) *Promise[T] {
|
||||||
|
return &Promise[T]{
|
||||||
|
err: err,
|
||||||
|
pending: false,
|
||||||
|
mu: &sync.Mutex{},
|
||||||
|
wg: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Promise[T]) reject(err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if !p.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.err = err
|
||||||
|
p.pending = false
|
||||||
|
|
||||||
|
p.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then allows chain calls to other promise methods.
|
||||||
|
func Then[T1, T2 any](promise *Promise[T1], resolve1 func(value T1) T2) *Promise[T2] {
|
||||||
|
return New(func(resolve2 func(T2), reject func(error)) {
|
||||||
|
result, err := promise.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve2(resolve1(result))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then allows chain calls to other promise methods.
|
||||||
|
func (p *Promise[T]) Then(resolve func(value T) T) *Promise[T] {
|
||||||
|
return New(func(_resolve func(T), reject func(error)) {
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_resolve(resolve(result))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch allows to chain promises.
|
||||||
|
func Catch[T any](promise *Promise[T], rejection func(err error) error) *Promise[T] {
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
result, err := promise.Await()
|
||||||
|
if err != nil {
|
||||||
|
reject(rejection(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch chain an existing promise with an intermediate reject function.
|
||||||
|
func (p *Promise[T]) Catch(reject func(error) error) *Promise[T] {
|
||||||
|
return New(func(resolve func(T), rej func(error)) {
|
||||||
|
resutl, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
rej(reject(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(resutl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Await blocks until the 'runable' to finish execution.
|
||||||
|
func (p *Promise[T]) Await() (T, error) {
|
||||||
|
p.wg.Wait()
|
||||||
|
return p.result, p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type tuple[T1, T2 any] struct {
|
||||||
|
_1 T1
|
||||||
|
_2 T2
|
||||||
|
}
|
||||||
|
|
||||||
|
// All resolves when all of the promises have resolved, reject immediately upon any of the input promises rejecting.
|
||||||
|
func All[T any](promises []*Promise[T]) *Promise[[]T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func([]T), reject func(error)) {
|
||||||
|
valsChan := make(chan tuple[T, int], len(promises))
|
||||||
|
errsChan := make(chan error, 1)
|
||||||
|
|
||||||
|
for idx, p := range promises {
|
||||||
|
idx := idx
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- tuple[T, int]{_1: data, _2: idx}
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- err
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resolutions := make([]T, len(promises))
|
||||||
|
for idx := 0; idx < len(promises); idx++ {
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolutions[val._2] = val._1
|
||||||
|
case err := <-errsChan:
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(resolutions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Race will settle the first fullfiled promise among muti promises.
|
||||||
|
func Race[T any](promises []*Promise[T]) *Promise[T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
valsChan := make(chan T, 1)
|
||||||
|
errsChan := make(chan error, 1)
|
||||||
|
|
||||||
|
for _, p := range promises {
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- data
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- err
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolve(val)
|
||||||
|
case err := <-errsChan:
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any resolves as soon as any of the input's Promises resolve, with the value of the resolved Promise.
|
||||||
|
// Any rejects if all of the given Promises are rejected with a combination of all errors.
|
||||||
|
func Any[T any](promises []*Promise[T]) *Promise[T] {
|
||||||
|
if len(promises) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(func(resolve func(T), reject func(error)) {
|
||||||
|
valsChan := make(chan T, 1)
|
||||||
|
errsChan := make(chan tuple[error, int], len(promises))
|
||||||
|
|
||||||
|
for idx, p := range promises {
|
||||||
|
idx := idx
|
||||||
|
_ = Then(p, func(data T) T {
|
||||||
|
valsChan <- data
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
_ = Catch(p, func(err error) error {
|
||||||
|
errsChan <- tuple[error, int]{_1: err, _2: idx}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := make([]error, len(promises))
|
||||||
|
for idx := 0; idx < len(promises); idx++ {
|
||||||
|
select {
|
||||||
|
case val := <-valsChan:
|
||||||
|
resolve(val)
|
||||||
|
return
|
||||||
|
case err := <-errsChan:
|
||||||
|
errs[err._2] = err._1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errCombo := errs[0]
|
||||||
|
for _, err := range errs[1:] {
|
||||||
|
errCombo = internal.JoinError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(errCombo)
|
||||||
|
})
|
||||||
|
}
|
||||||
195
async/promise_example_test.go
Normal file
195
async/promise_example_test.go
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
package async
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNew() {
|
||||||
|
p := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello")
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(val)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleThen() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello ")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Then(p1, func(s string) string {
|
||||||
|
return s + "world"
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := p2.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExamplePromise_Then() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("hello ")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Then(func(s string) string {
|
||||||
|
return s + "world"
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := p2.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCatch() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Catch(p1, func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := p1.Await()
|
||||||
|
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
result2, err := p2.Await()
|
||||||
|
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error1
|
||||||
|
//
|
||||||
|
// error1
|
||||||
|
// error2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExamplePromise_Catch() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Catch(func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := p1.Await()
|
||||||
|
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
result2, err := p2.Await()
|
||||||
|
|
||||||
|
fmt.Println(result2)
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// error1
|
||||||
|
//
|
||||||
|
// error1
|
||||||
|
// error2
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAll() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("c")
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2, p3}
|
||||||
|
p := All(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [a b c]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleAny() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error"))
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2, p3}
|
||||||
|
p := Any(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// fast
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRace() {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
|
||||||
|
pms := []*Promise[string]{p1, p2}
|
||||||
|
p := Race(pms)
|
||||||
|
|
||||||
|
result, err := p.Await()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// fast
|
||||||
|
}
|
||||||
302
async/promise_test.go
Normal file
302
async/promise_test.go
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
package async
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolve(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestResolve")
|
||||||
|
|
||||||
|
p := Resolve("abc")
|
||||||
|
|
||||||
|
assert.Equal("abc", p.result)
|
||||||
|
assert.Equal(false, p.pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReject(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReject")
|
||||||
|
|
||||||
|
err := errors.New("error")
|
||||||
|
p := Reject[string](err)
|
||||||
|
|
||||||
|
assert.Equal("error", p.err.Error())
|
||||||
|
assert.Equal(false, p.pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThen(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestThen")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("abc")
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Then(p1, func(data string) string {
|
||||||
|
return data + "de"
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("abc", val)
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal("abcde", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromise_Then(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Then")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(int), reject func(error)) {
|
||||||
|
resolve(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Then(func(n int) int {
|
||||||
|
return n + 2
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(1, val)
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
assert.IsNil(err)
|
||||||
|
assert.Equal(3, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCatch(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestCatch")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := Catch(p1, func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1", err.Error())
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1\nerror2", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromise_Catch(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Catch")
|
||||||
|
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
err := errors.New("error1")
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
p2 := p1.Catch(func(err error) error {
|
||||||
|
e := errors.New("error2")
|
||||||
|
return internal.JoinError(err, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
val, err := p1.Await()
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1", err.Error())
|
||||||
|
|
||||||
|
val, err = p2.Await()
|
||||||
|
|
||||||
|
assert.Equal("", val)
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
assert.Equal("error1\nerror2", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAll(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_All")
|
||||||
|
|
||||||
|
t.Run("AllPromisesFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("c")
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal([]string{"a", "b", "c"}, val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := All(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error3"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := All([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAny(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Any")
|
||||||
|
|
||||||
|
t.Run("AnyFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
resolve("fast")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 500)
|
||||||
|
resolve("slow")
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Any([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal("fast", val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := Any(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Any([]*Promise[string]{p1, p2})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRace(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPromise_Race")
|
||||||
|
|
||||||
|
t.Run("PromisesFullfilled", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
resolve("b")
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
assert.Equal("a", val)
|
||||||
|
assert.IsNil(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmptyPromises", func(_ *testing.T) {
|
||||||
|
var empty = []*Promise[any]{}
|
||||||
|
p := Race(empty)
|
||||||
|
assert.IsNil(p)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesContainRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
resolve("a")
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
val, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
assert.Equal("", val)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("PromisesOnlyRejected", func(_ *testing.T) {
|
||||||
|
p1 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error1"))
|
||||||
|
|
||||||
|
})
|
||||||
|
p2 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error2"))
|
||||||
|
})
|
||||||
|
p3 := New(func(resolve func(string), reject func(error)) {
|
||||||
|
reject(errors.New("error3"))
|
||||||
|
})
|
||||||
|
|
||||||
|
p := Race([]*Promise[string]{p1, p2, p3})
|
||||||
|
|
||||||
|
_, err := p.Await()
|
||||||
|
|
||||||
|
assert.IsNotNil(err)
|
||||||
|
// assert.Equal("error1", err.Error())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
// Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||||
package concurrency
|
package concurrency
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -171,3 +171,25 @@ func (s Set[T]) Minus(comparedSet Set[T]) Set[T] {
|
|||||||
|
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EachWithBreak iterates over elements of a set and invokes function for each element,
|
||||||
|
// when iteratee return false, will break the for each loop.
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool) {
|
||||||
|
for v := range s {
|
||||||
|
if !iteratee(v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop delete the top element of set then return it, if set is empty, return nil-value of T and false.
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool) {
|
||||||
|
if len(s) > 0 {
|
||||||
|
items := s.Values()
|
||||||
|
item := items[len(s)-1]
|
||||||
|
delete(s, item)
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|||||||
@@ -192,3 +192,40 @@ func TestSet_Minus(t *testing.T) {
|
|||||||
assert.Equal(NewSet(1), set1.Minus(set2))
|
assert.Equal(NewSet(1), set1.Minus(set2))
|
||||||
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
assert.Equal(NewSet(4, 5), set2.Minus(set3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEachWithBreak(t *testing.T) {
|
||||||
|
s := NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
s.EachWithBreak(func(n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestEachWithBreak")
|
||||||
|
assert.Equal(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func TestPop(t *testing.T) {
|
||||||
|
// assert := internal.NewAssert(t, "TestPop")
|
||||||
|
|
||||||
|
// s := NewSet[int]()
|
||||||
|
|
||||||
|
// val, ok := s.Pop()
|
||||||
|
// assert.Equal(0, val)
|
||||||
|
// assert.Equal(false, ok)
|
||||||
|
|
||||||
|
// s.Add(1)
|
||||||
|
// s.Add(2)
|
||||||
|
// s.Add(3)
|
||||||
|
|
||||||
|
// // s = NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
// val, ok = s.Pop()
|
||||||
|
// assert.Equal(3, val)
|
||||||
|
// assert.Equal(true, ok)
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Concurrency
|
# Concurrency
|
||||||
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel, async.
|
Package concurrency contain some functions to support concurrent programming. eg, goroutine, channel.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Concurrency
|
# Concurrency
|
||||||
并发包包含一些支持并发编程的功能。例如:goroutine, channel, async等。
|
并发包包含一些支持并发编程的功能。例如:goroutine, channel等。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Set
|
# Set
|
||||||
|
|
||||||
Set is a data container, like list, but elements of set is not duplicate.
|
Set is a data container, like list, but elements of set is not duplicate.
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -7,10 +8,10 @@ Set is a data container, like list, but elements of set is not duplicate.
|
|||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
@@ -34,19 +35,19 @@ import (
|
|||||||
- [Size](#Size)
|
- [Size](#Size)
|
||||||
- [Equal](#Equal)
|
- [Equal](#Equal)
|
||||||
- [Iterate](#Iterate)
|
- [Iterate](#Iterate)
|
||||||
|
- [EachWithBreak](#EachWithBreak)
|
||||||
- [IsEmpty](#IsEmpty)
|
- [IsEmpty](#IsEmpty)
|
||||||
- [Union](#Union)
|
- [Union](#Union)
|
||||||
- [Intersection](#Intersection)
|
- [Intersection](#Intersection)
|
||||||
- [SymmetricDifference](#SymmetricDifference)
|
- [SymmetricDifference](#SymmetricDifference)
|
||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### <span id="NewSet">NewSet</span>
|
### <span id="NewSet">NewSet</span>
|
||||||
|
|
||||||
<p>Create a set instance</p>
|
<p>Create a set instance</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -55,6 +56,7 @@ import (
|
|||||||
type Set[T comparable] map[T]bool
|
type Set[T comparable] map[T]bool
|
||||||
func NewSet[T comparable](items ...T) Set[T]
|
func NewSet[T comparable](items ...T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -71,8 +73,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||||
|
|
||||||
<p>Create a set from slice</p>
|
<p>Create a set from slice</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -80,6 +82,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -96,9 +99,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Values">Values</span>
|
### <span id="Values">Values</span>
|
||||||
|
|
||||||
<p>Return slice of all set data</p>
|
<p>Return slice of all set data</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -106,6 +108,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Values() []T
|
func (s Set[T]) Values() []T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -122,10 +125,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Add">Add</span>
|
### <span id="Add">Add</span>
|
||||||
|
|
||||||
<p>Add items to set</p>
|
<p>Add items to set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -133,6 +134,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Add(items ...T)
|
func (s Set[T]) Add(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -151,8 +153,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||||
|
|
||||||
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
|
<p>AddIfNotExist checks if item exists in the set, it adds the item to set and returns true if it does not exist in the set, or else it does nothing and returns false.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -160,6 +162,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExist(item T) bool
|
func (s Set[T]) AddIfNotExist(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -183,8 +186,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||||
|
|
||||||
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
|
<p>AddIfNotExistBy checks if item exists in the set and pass the `checker` function it adds the item to set and returns true if it does not exists in the set and function `checker` returns true, or else it does nothing and returns false.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -192,6 +195,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -221,8 +225,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delete">Delete</span>
|
### <span id="Delete">Delete</span>
|
||||||
|
|
||||||
<p>Delete item in set</p>
|
<p>Delete item in set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -230,6 +234,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Delete(items ...T)
|
func (s Set[T]) Delete(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -249,9 +254,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Contain">Contain</span>
|
### <span id="Contain">Contain</span>
|
||||||
|
|
||||||
<p>Check if item is in set or not</p>
|
<p>Check if item is in set or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -259,6 +263,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Contain(item T) bool
|
func (s Set[T]) Contain(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -278,10 +283,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ContainAll">ContainAll</span>
|
### <span id="ContainAll">ContainAll</span>
|
||||||
|
|
||||||
<p>Checks if set contains another set</p>
|
<p>Checks if set contains another set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -289,6 +292,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -309,9 +313,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Size">Size</span>
|
### <span id="Size">Size</span>
|
||||||
|
|
||||||
<p>Get the number of elements in set</p>
|
<p>Get the number of elements in set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -319,6 +322,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Size() int
|
func (s Set[T]) Size() int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -336,9 +340,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Clone">Clone</span>
|
### <span id="Clone">Clone</span>
|
||||||
|
|
||||||
<p>Make a copy of set</p>
|
<p>Make a copy of set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -346,6 +349,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Clone() Set[T]
|
func (s Set[T]) Clone() Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -365,10 +369,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Equal">Equal</span>
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
<p>Check if two sets has same elements or not</p>
|
<p>Check if two sets has same elements or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -376,6 +378,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Equal(other Set[T]) bool
|
func (s Set[T]) Equal(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -396,9 +399,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Iterate">Iterate</span>
|
### <span id="Iterate">Iterate</span>
|
||||||
|
|
||||||
<p>Call function by every element of set</p>
|
<p>Call function by every element of set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -406,6 +408,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Iterate(fn func(item T))
|
func (s Set[T]) Iterate(fn func(item T))
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -427,9 +430,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EachWithBreak">EachWithBreak</span>
|
||||||
|
|
||||||
|
<p>Iterates over elements of a set and invokes function for each element, when iteratee return false, will break the for each loop.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
s.EachWithBreak(func(n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum) //6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsEmpty">IsEmpty</span>
|
### <span id="IsEmpty">IsEmpty</span>
|
||||||
|
|
||||||
<p>Check if the set is empty or not</p>
|
<p>Check if the set is empty or not</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -437,6 +476,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) IsEmpty() bool
|
func (s Set[T]) IsEmpty() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -456,9 +496,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>Create a new set contain all element of set s and other</p>
|
<p>Create a new set contain all element of set s and other</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -466,6 +505,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -485,9 +525,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Intersection">Intersection</span>
|
### <span id="Intersection">Intersection</span>
|
||||||
|
|
||||||
<p>Create a new set whose element both be contained in set s and other</p>
|
<p>Create a new set whose element both be contained in set s and other</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -495,6 +534,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -514,11 +554,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||||
|
|
||||||
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
|
<p>Create a new set whose element is in set1 or set2, but not in both set1 and set2</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -526,6 +563,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -545,11 +583,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Minus">Minus</span>
|
### <span id="Minus">Minus</span>
|
||||||
|
|
||||||
<p>Create an set of whose element in origin set but not in compared set</p>
|
<p>Create an set of whose element in origin set but not in compared set</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
@@ -557,6 +592,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -580,5 +616,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pop">Pop</span>
|
||||||
|
|
||||||
|
<p>Delete the top element of set then return it, if set is empty, return nil-value of T and false.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet[int]()
|
||||||
|
s.Add(1)
|
||||||
|
s.Add(2)
|
||||||
|
s.Add(3)
|
||||||
|
|
||||||
|
val, ok = s.Pop()
|
||||||
|
|
||||||
|
fmt.Println(val) // 3
|
||||||
|
fmt.Println(ok) // true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Set
|
# Set
|
||||||
|
|
||||||
Set 集合数据结构,类似列表。Set 中元素不重复。
|
Set 集合数据结构,类似列表。Set 中元素不重复。
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -7,10 +8,10 @@ Set集合数据结构,类似列表。Set中元素不重复。
|
|||||||
|
|
||||||
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
- [https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go](https://github.com/duke-git/lancet/blob/main/datastructure/set/set.go)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 用法
|
## 用法
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
set "github.com/duke-git/lancet/v2/datastructure/set"
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
@@ -40,13 +41,12 @@ import (
|
|||||||
- [SymmetricDifference](#SymmetricDifference)
|
- [SymmetricDifference](#SymmetricDifference)
|
||||||
- [Minus](#Minus)
|
- [Minus](#Minus)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
### <span id="NewSet">NewSet</span>
|
### <span id="NewSet">NewSet</span>
|
||||||
|
|
||||||
<p>返回Set结构体对象</p>
|
<p>返回Set结构体对象</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -55,6 +55,7 @@ import (
|
|||||||
type Set[T comparable] map[T]bool
|
type Set[T comparable] map[T]bool
|
||||||
func NewSet[T comparable](items ...T) Set[T]
|
func NewSet[T comparable](items ...T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -71,9 +72,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
### <span id="NewSetFromSlice">NewSetFromSlice</span>
|
||||||
|
|
||||||
<p>基于切片创建集合</p>
|
<p>基于切片创建集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -81,6 +81,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func NewSetFromSlice[T comparable](items []T) Set[T]
|
func NewSetFromSlice[T comparable](items []T) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -97,9 +98,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Values">Values</span>
|
### <span id="Values">Values</span>
|
||||||
|
|
||||||
<p>获取集合中所有元素的切片</p>
|
<p>获取集合中所有元素的切片</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -107,6 +107,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Values() []T
|
func (s Set[T]) Values() []T
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -123,10 +124,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Add">Add</span>
|
### <span id="Add">Add</span>
|
||||||
|
|
||||||
<p>向集合中添加元素</p>
|
<p>向集合中添加元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -134,6 +133,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Add(items ...T)
|
func (s Set[T]) Add(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -152,8 +152,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExist">AddIfNotExist</span>
|
### <span id="AddIfNotExist">AddIfNotExist</span>
|
||||||
|
|
||||||
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
|
<p>如果集合中不存在元素,则添加该元素返回true, 如果集合中存在元素, 不做任何操作,返回false</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -161,6 +161,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExist(item T) bool
|
func (s Set[T]) AddIfNotExist(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -184,8 +185,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
### <span id="AddIfNotExistBy">AddIfNotExistBy</span>
|
||||||
|
|
||||||
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
|
<p>根据checker函数判断元素是否在集合中,如果集合中不存在元素且checker返回true,则添加该元素返回true, 否则不做任何操作,返回false</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -193,6 +194,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
func (s Set[T]) AddIfNotExistBy(item T, checker func(element T) bool) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -222,9 +224,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Delete">Delete</span>
|
### <span id="Delete">Delete</span>
|
||||||
|
|
||||||
<p>删除集合中元素</p>
|
<p>删除集合中元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -232,6 +233,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Delete(items ...T)
|
func (s Set[T]) Delete(items ...T)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -251,9 +253,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Contain">Contain</span>
|
### <span id="Contain">Contain</span>
|
||||||
|
|
||||||
<p>判断集合是否包含某个值</p>
|
<p>判断集合是否包含某个值</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -261,6 +262,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Contain(item T) bool
|
func (s Set[T]) Contain(item T) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -280,10 +282,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="ContainAll">ContainAll</span>
|
### <span id="ContainAll">ContainAll</span>
|
||||||
|
|
||||||
<p>判断集合是否包含另一个集合</p>
|
<p>判断集合是否包含另一个集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -291,6 +291,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) ContainAll(other Set[T]) bool
|
func (s Set[T]) ContainAll(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -311,9 +312,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Size">Size</span>
|
### <span id="Size">Size</span>
|
||||||
|
|
||||||
<p>获取集合中元素的个数</p>
|
<p>获取集合中元素的个数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -321,6 +321,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Size() int
|
func (s Set[T]) Size() int
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -338,9 +339,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Clone">Clone</span>
|
### <span id="Clone">Clone</span>
|
||||||
|
|
||||||
<p>克隆一个集合</p>
|
<p>克隆一个集合</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -348,6 +348,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Clone() Set[T]
|
func (s Set[T]) Clone() Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -367,10 +368,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Equal">Equal</span>
|
### <span id="Equal">Equal</span>
|
||||||
|
|
||||||
<p>比较两个集合是否相等,包含相同元素为相等</p>
|
<p>比较两个集合是否相等,包含相同元素为相等</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -378,6 +377,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Equal(other Set[T]) bool
|
func (s Set[T]) Equal(other Set[T]) bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -398,9 +398,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Iterate">Iterate</span>
|
### <span id="Iterate">Iterate</span>
|
||||||
|
|
||||||
<p>迭代结合,在每个元素上调用函数</p>
|
<p>迭代结合,在每个元素上调用函数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -408,6 +407,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Iterate(fn func(item T))
|
func (s Set[T]) Iterate(fn func(item T))
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -429,9 +429,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="EachWithBreak">EachWithBreak</span>
|
||||||
|
|
||||||
|
<p>遍历集合的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) EachWithBreak(iteratee func(item T) bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet(1, 2, 3, 4, 5)
|
||||||
|
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
s.EachWithBreak(func(n int) bool {
|
||||||
|
if n > 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sum += n
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(sum) //6
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="IsEmpty">IsEmpty</span>
|
### <span id="IsEmpty">IsEmpty</span>
|
||||||
|
|
||||||
<p>判断集合是否为空</p>
|
<p>判断集合是否为空</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -439,6 +475,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) IsEmpty() bool
|
func (s Set[T]) IsEmpty() bool
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -458,9 +495,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>求两个集合的并集</p>
|
<p>求两个集合的并集</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -468,6 +504,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Union(other Set[T]) Set[T]
|
func (s Set[T]) Union(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -487,9 +524,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Intersection">Intersection</span>
|
### <span id="Intersection">Intersection</span>
|
||||||
|
|
||||||
<p>求两个集合的交集</p>
|
<p>求两个集合的交集</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -497,6 +533,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
func (s Set[T]) Intersection(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -516,8 +553,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="SymmetricDifference">SymmetricDifference</span>
|
### <span id="SymmetricDifference">SymmetricDifference</span>
|
||||||
|
|
||||||
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
<p>返回一个集合,其中元素在第一个集合或第二个集合中,且不同时存在于两个集合中</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -525,6 +562,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -544,11 +582,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Minus">Minus</span>
|
### <span id="Minus">Minus</span>
|
||||||
|
|
||||||
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
|
<p>创建一个集合,其元素在原始集中但不在比较集中</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
@@ -556,6 +591,7 @@ func main() {
|
|||||||
```go
|
```go
|
||||||
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
func (s Set[T]) Minus(comparedSet Set[T]) Set[T]
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>示例:</b>
|
<b>示例:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -579,5 +615,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="Pop">Pop</span>
|
||||||
|
|
||||||
|
<p>删除并返回集合中的顶部元素</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s Set[T]) Pop() (v T, ok bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
set "github.com/duke-git/lancet/v2/datastructure/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := set.NewSet[int]()
|
||||||
|
s.Add(1)
|
||||||
|
s.Add(2)
|
||||||
|
s.Add(3)
|
||||||
|
|
||||||
|
val, ok = s.Pop()
|
||||||
|
|
||||||
|
fmt.Println(val) // 3
|
||||||
|
fmt.Println(ok) // true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1002,10 +1002,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
<p>Iterates over elements of slice and invokes function for each element, when iteratee return true, will break the for each loop.</p>
|
<p>Iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -542,7 +542,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="Drop">Drop</span>
|
### <span id="Drop">Drop</span>
|
||||||
|
|
||||||
<p>从切片的头部删除n个元素。</p>
|
<p>从切片的头部删除n个元素。</p>
|
||||||
@@ -1004,7 +1003,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
### <span id="ForEachWithBreak">ForEachWithBreak</span>
|
||||||
|
|
||||||
<p>遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
<p>遍历切片的元素并为每个元素调用iteratee函数,当iteratee函数返回false时,终止遍历。</p>
|
||||||
@@ -1043,7 +1041,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="GroupBy">GroupBy</span>
|
### <span id="GroupBy">GroupBy</span>
|
||||||
|
|
||||||
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
<p>迭代切片的元素,每个元素将按条件分组,返回两个切片</p>
|
||||||
|
|||||||
@@ -79,16 +79,18 @@ func (a *Assert) LessOrEqual(expected, actual any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsNil check if value is nil
|
// IsNil check if value is nil
|
||||||
func (a *Assert) IsNil(value any) {
|
func (a *Assert) IsNil(v any) {
|
||||||
if value != nil {
|
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||||
makeTestFailed(a.T, a.CaseName, nil, value)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeTestFailed(a.T, a.CaseName, nil, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotNil check if value is not nil
|
// IsNotNil check if value is not nil
|
||||||
func (a *Assert) IsNotNil(value any) {
|
func (a *Assert) IsNotNil(v any) {
|
||||||
if value == nil {
|
if v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) {
|
||||||
makeTestFailed(a.T, a.CaseName, "not nil", value)
|
makeTestFailed(a.T, a.CaseName, "not nil", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
internal/error_join.go
Normal file
51
internal/error_join.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
// Note: this file is copyed from the go standart repo (https://github.com/golang/go/blob/master/src/errors/join.go).
|
||||||
|
// just in order to adapt under go1.9
|
||||||
|
// do not use it outside lancet lib.
|
||||||
|
|
||||||
|
// Join returns an error that wraps the given errors.
|
||||||
|
// Any nil error values are discarded.
|
||||||
|
// Join returns nil if errs contains no non-nil values.
|
||||||
|
// The error formats as the concatenation of the strings obtained
|
||||||
|
// by calling the Error method of each element of errs, with a newline
|
||||||
|
// between each string.
|
||||||
|
func JoinError(errs ...error) error {
|
||||||
|
n := 0
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e := &joinError{
|
||||||
|
errs: make([]error, 0, n),
|
||||||
|
}
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
e.errs = append(e.errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
type joinError struct {
|
||||||
|
errs []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *joinError) Error() string {
|
||||||
|
var b []byte
|
||||||
|
for i, err := range e.errs {
|
||||||
|
if i > 0 {
|
||||||
|
b = append(b, '\n')
|
||||||
|
}
|
||||||
|
b = append(b, err.Error()...)
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *joinError) Unwrap() []error {
|
||||||
|
return e.errs
|
||||||
|
}
|
||||||
@@ -422,12 +422,11 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
// ForEachWithBreak iterates over elements of slice and invokes function for each element,
|
||||||
// when iteratee return true, will break the for each loop.
|
// when iteratee return false, will break the for each loop.
|
||||||
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
func ForEachWithBreak[T any](slice []T, iteratee func(index int, item T) bool) {
|
||||||
loop:
|
|
||||||
for i, v := range slice {
|
for i, v := range slice {
|
||||||
if !iteratee(i, v) {
|
if !iteratee(i, v) {
|
||||||
break loop
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package structs provide several high level functions to manipulate struct, tag, and field.
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
Reference in New Issue
Block a user