From e138043289d80efdcf9bd5a6f5d362268e053f11 Mon Sep 17 00:00:00 2001 From: donutloop Date: Mon, 4 Mar 2024 03:00:43 +0100 Subject: [PATCH] Function: AcceptIf (#198) AcceptIf returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure. A predicate function that takes an argument of type T and returns a bool. An apply function that also takes an argument of type T and returns a modified value of the same type. --- docs/api/packages/function.md | 53 +++++++++++++++++++++++++++ docs/en/api/packages/function.md | 54 ++++++++++++++++++++++++++++ function/function.go | 21 +++++++++++ function/function_example_test.go | 29 +++++++++++++++ function/function_test.go | 60 +++++++++++++++++++++++++++++++ 5 files changed, 217 insertions(+) diff --git a/docs/api/packages/function.md b/docs/api/packages/function.md index 284f6fc..d338125 100644 --- a/docs/api/packages/function.md +++ b/docs/api/packages/function.md @@ -39,6 +39,8 @@ import ( - [Nor](#Nor) - [Xnor](#Xnor) - [Nand](#Nand) +- [AcceptIf](#AcceptIf) +
@@ -638,4 +640,55 @@ func main() { // true // false } +``` + +### AcceptIf + +

TBD

+ +函数签名: + +```go +func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool) +``` + +示例: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/function" +) + +func main() { + + adder := AcceptIf( + And( + func(x int) bool { + return x > 10 + }, func(x int) bool { + return x%2 == 0 + }), + func(x int) int { + return x + 1 + }, + ) + + result, ok := adder(20) + fmt.Println(result) + fmt.Println(ok) + + result, ok = adder(21) + fmt.Println(result) + fmt.Println(ok) + + // Output: + // 21 + // true + // 0 + // false +} + ``` \ No newline at end of file diff --git a/docs/en/api/packages/function.md b/docs/en/api/packages/function.md index c810b92..8e798ae 100644 --- a/docs/en/api/packages/function.md +++ b/docs/en/api/packages/function.md @@ -39,6 +39,7 @@ import ( - [Nor](#Nor) - [Xnor](#Xnor) - [Nand](#Nand) +- [AcceptIf](#AcceptIf)
@@ -638,4 +639,57 @@ func main() { // true // false } +``` + +### AcceptIf + +

AcceptIf returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure. +A predicate function that takes an argument of type T and returns a bool. +An apply function that also takes an argument of type T and returns a modified value of the same type.

+ +Signature: + +```go +func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool) +``` + +Example: + +```go +package main + +import ( + "fmt" + "github.com/duke-git/lancet/v2/function" +) + +func main() { + + adder := AcceptIf( + And( + func(x int) bool { + return x > 10 + }, func(x int) bool { + return x%2 == 0 + }), + func(x int) int { + return x + 1 + }, + ) + + result, ok := adder(20) + fmt.Println(result) + fmt.Println(ok) + + result, ok = adder(21) + fmt.Println(result) + fmt.Println(ok) + + // Output: + // 21 + // true + // 0 + // false +} + ``` \ No newline at end of file diff --git a/function/function.go b/function/function.go index 5919fe5..0840983 100644 --- a/function/function.go +++ b/function/function.go @@ -136,6 +136,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T { } } +// AcceptIf returns another function of the same signature as the apply function but also includes a bool value to indicate success or failure. +// A predicate function that takes an argument of type T and returns a bool. +// An apply function that also takes an argument of type T and returns a modified value of the same type. +func AcceptIf[T any](predicate func(T) bool, apply func(T) T) func(T) (T, bool) { + if predicate == nil { + panic("programming error: predicate must be not nil") + } + + if apply == nil { + panic("programming error: apply must be not nil") + } + + return func(t T) (T, bool) { + if !predicate(t) { + var defaultValue T + return defaultValue, false + } + return apply(t), true + } +} + func unsafeInvokeFunc(fn any, args ...any) []reflect.Value { fv := reflect.ValueOf(fn) params := make([]reflect.Value, len(args)) diff --git a/function/function_example_test.go b/function/function_example_test.go index 5350273..f4d9562 100644 --- a/function/function_example_test.go +++ b/function/function_example_test.go @@ -145,3 +145,32 @@ func ExamplePipeline() { // Output: // 36 } + +func ExampleAcceptIf() { + + adder := AcceptIf( + And( + func(x int) bool { + return x > 10 + }, func(x int) bool { + return x%2 == 0 + }), + func(x int) int { + return x + 1 + }, + ) + + result, ok := adder(20) + fmt.Println(result) + fmt.Println(ok) + + result, ok = adder(21) + fmt.Println(result) + fmt.Println(ok) + + // Output: + // 21 + // true + // 0 + // false +} diff --git a/function/function_test.go b/function/function_test.go index c9f3751..18fe547 100644 --- a/function/function_test.go +++ b/function/function_test.go @@ -162,3 +162,63 @@ func TestPipeline(t *testing.T) { assert.Equal(36, f(2)) } + +func TestAcceptIf(t *testing.T) { + assert := internal.NewAssert(t, "AcceptIf") + + adder := AcceptIf( + And( + func(x int) bool { + return x > 10 + }, func(x int) bool { + return x%2 == 0 + }), + func(x int) int { + return x + 1 + }, + ) + + result, ok := adder(20) + assert.Equal(21, result) + assert.Equal(true, ok) + + result, ok = adder(21) + assert.Equal(0, result) + assert.Equal(false, ok) +} + +func TestAcceptIfPanicMissingPredicate(t *testing.T) { + t.Parallel() + + assert := internal.NewAssert(t, "TestAcceptIfPanicMissingPredicate") + + defer func() { + v := recover() + assert.Equal("programming error: predicate must be not nil", v) + }() + + AcceptIf( + nil, + func(x int) int { + return x + }, + ) +} + +func TestAcceptIfPanicMissingApply(t *testing.T) { + t.Parallel() + + assert := internal.NewAssert(t, "TestAcceptIfPanicMissingApply") + + defer func() { + v := recover() + assert.Equal("programming error: apply must be not nil", v) + }() + + AcceptIf( + func(i int) bool { + return false + }, + nil, + ) +}