Go中的一类函数
我来自JavaScript,它有一流的函数支持。例如,您可以:Go中的一类函数,go,functional-programming,Go,Functional Programming,我来自JavaScript,它有一流的函数支持。例如,您可以: 将函数作为参数传递给另一个函数 从函数返回函数 有人能给我举个例子,说明我在围棋中是如何做到这一点的吗?可能会有所帮助。从这篇博文: package main import fmt "fmt" type Stringy func() string func foo() string{ return "Stringy function" } func takesAFunction(foo Stringy){
- 将函数作为参数传递给另一个函数
- 从函数返回函数
package main
import fmt "fmt"
type Stringy func() string
func foo() string{
return "Stringy function"
}
func takesAFunction(foo Stringy){
fmt.Printf("takesAFunction: %v\n", foo())
}
func returnsAFunction()Stringy{
return func()string{
fmt.Printf("Inner stringy function\n");
return "bar" // have to return a string to be stringy
}
}
func main(){
takesAFunction(foo);
var f Stringy = returnsAFunction();
f();
var baz Stringy = func()string{
return "anonymous stringy\n"
};
fmt.Printf(baz());
}
作者是博客所有者:DetheElza(不是我)规范中的相关部分: 这里的所有其他答案都首先声明了一个新类型,这是一个好的(实践)方法,使代码更易于阅读,但要知道这不是一个要求 您可以在不为函数值声明新类型的情况下使用函数值,如下面的示例所示 声明一个函数类型的变量,该变量有两个
float64
类型的参数,并且有一个float64
类型的返回值,如下所示:
// Create a var of the mentioned function type:
var f func(float64, float64) float64
让我们编写一个返回加法器函数的函数。此加法器函数应采用2个float64
类型的参数,调用时应返回这2个数字的总和:
func CreateAdder() func(float64, float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
让我们编写一个有3个参数的函数,前2个是float64
类型,第3个是函数值,一个接受float64
类型的2个输入参数并生成float64
类型的值的函数。我们正在编写的函数将调用作为参数传递给它的函数值,并使用前2个float64
值作为函数值的参数,并返回传递的函数值返回的结果:
func Execute(a, b float64, op func(float64, float64) float64) float64 {
return op(a, b)
}
让我们看看前面的例子:
var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
func TestDummy(t *testing.T) {
c, final := MakeChain()
c(mw1(`OK!`))(mw2(t, `OK!`))(nil)
log.Println(final)
w1 := httptest.NewRecorder()
r1, err := http.NewRequest("GET", "/api/v1", nil)
if err != nil {
t.Fatal(err)
}
final.ServeHTTP(w1, r1)
}
func mw2(t *testing.T, expectedState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
val := r.Context().Value(contextKey("state"))
sval := fmt.Sprintf("%v", val)
assert.Equal(t, sval, expectedState)
})
}
}
func mw1(initialState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), contextKey("state"), initialState)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
type contextKey string
请注意,在创建加法器时,当然可以使用:
adder := CreateAdder() // adder is of type: func(float64, float64) float64
请在桌面上尝试这些示例
使用现有函数
当然,如果您已经在具有相同函数类型的包中声明了一个函数,那么您也可以使用它
例如,具有相同的函数类型:
func Mod(x, y float64) float64
因此,您可以将此值传递给我们的Execute()
函数:
fmt.Println(Execute(12, 10, math.Mod)) // Prints 2
打印2
,因为12 mod 10=2
。请注意,现有函数的名称充当函数值
试穿一下
注意:
请注意,参数名称不是类型的一部分,具有相同参数和结果类型的2个函数的类型是相同的,而不管参数名称如何。但是要知道,在参数或结果列表中,名称必须全部存在或全部不存在
例如,你也可以写:
func CreateAdder() func(P float64, Q float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
或:
虽然可以使用var或声明类型,但不需要这样做。
您可以非常简单地执行此操作:
package main
import "fmt"
var count int
func increment(i int) int {
return i + 1
}
func decrement(i int) int {
return i - 1
}
func execute(f func(int) int) int {
return f(count)
}
func main() {
count = 2
count = execute(increment)
fmt.Println(count)
count = execute(decrement)
fmt.Println(count)
}
//The output is:
3
2
这只是一个带有递归函数定义的脑筋急转弯,用于链接web应用程序中的中间件
首先,工具箱:
func MakeChain() (Chain, http.Handler) {
nop := http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {})
var list []Middleware
var final http.Handler = nop
var f Chain
f = func(m Middleware) Chain {
if m != nil {
list = append(list, m)
} else {
for i := len(list) - 1; i >= 0; i-- {
mid := list[i]
if mid == nil {
continue
}
if next := mid(final); next != nil {
final = next
} else {
final = nop
}
}
if final == nil {
final = nop
}
return nil
}
return f
}
return f, final
}
type (
Middleware func(http.Handler) http.Handler
Chain func(Middleware) Chain
)
正如您所看到的,typeChain
是一个函数,它返回相同类型的另一个函数Chain
(这是多么一流的!)
现在进行一些测试以查看它的运行情况:
var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
func TestDummy(t *testing.T) {
c, final := MakeChain()
c(mw1(`OK!`))(mw2(t, `OK!`))(nil)
log.Println(final)
w1 := httptest.NewRecorder()
r1, err := http.NewRequest("GET", "/api/v1", nil)
if err != nil {
t.Fatal(err)
}
final.ServeHTTP(w1, r1)
}
func mw2(t *testing.T, expectedState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
val := r.Context().Value(contextKey("state"))
sval := fmt.Sprintf("%v", val)
assert.Equal(t, sval, expectedState)
})
}
}
func mw1(initialState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), contextKey("state"), initialState)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
type contextKey string
同样,这只是一个脑筋急转弯,表明我们可以以不同的方式在Go中使用一流函数。就我个人而言,我现在用它作为路由器和处理中间件。还有这篇文章:你应该知道,将函数作为参数传递并返回它们不是函数编程。更正了问题中的术语。这是否回答了你的问题。
func TestDummy(t *testing.T) {
c, final := MakeChain()
c(mw1(`OK!`))(mw2(t, `OK!`))(nil)
log.Println(final)
w1 := httptest.NewRecorder()
r1, err := http.NewRequest("GET", "/api/v1", nil)
if err != nil {
t.Fatal(err)
}
final.ServeHTTP(w1, r1)
}
func mw2(t *testing.T, expectedState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
val := r.Context().Value(contextKey("state"))
sval := fmt.Sprintf("%v", val)
assert.Equal(t, sval, expectedState)
})
}
}
func mw1(initialState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), contextKey("state"), initialState)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
type contextKey string