Go中的头等功能

Dre*_*eur 51 functional-programming go

我来自JavaScript,它具有一流的功能支持.例如,你可以:

  • 将函数作为参数传递给另一个函数
  • 从函数返回一个函数.

有人能举例说明我将如何在Go中这样做吗?

小智 41

Go Language和Functional Programming可能会有所帮助.来自这篇博文:

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());
}
Run Code Online (Sandbox Code Playgroud)

作者是博主:Dethe Elza(不是我)


小智 27

package main

import (
    "fmt"
)

type Lx func(int) int

func cmb(f, g Lx) Lx {
    return func(x int) int {
        return g(f(x))
    }
}

func inc(x int) int {
    return x + 1
}

func sum(x int) int {
    result := 0

    for i := 0; i < x; i++ {
        result += i
    }

    return result
}

func main() {
    n := 666

    fmt.Println(cmb(inc, sum)(n))
    fmt.Println(n * (n + 1) / 2)
}
Run Code Online (Sandbox Code Playgroud)

输出:

222111
222111
Run Code Online (Sandbox Code Playgroud)


icz*_*cza 6

规范中的相关部分:函数类型.

这里的所有其他答案首先声明一个新类型,这是好的(练习)并使您的代码更容易阅读,但知道这不是一个要求.

您可以使用函数值而不为它们声明新类型,如下面的示例所示.

声明一个函数类型的变量,它有2个类型的参数,float64并且有一个类型的返回值,float64如下所示:

// Create a var of the mentioned function type:
var f func(float64, float64) float64
Run Code Online (Sandbox Code Playgroud)

让我们编写一个返回加法器函数的函数.此加法器函数应采用2个类型的参数,float64并应在调用时返回这2个数字的总和:

func CreateAdder() func(float64, float64) float64 {
    return func(x, y float64) float64 {
        return x + y
    }
}
Run Code Online (Sandbox Code Playgroud)

让我们编写一个函数,它有3个参数,前2个是类型float64,第3个是函数值,这个函数接受2个类型的输入参数float64并产生类型的值float64.我们正在编写的函数将调用作为参数传递给它的函数值,并使用前2个float64值作为函数值的参数,并返回传递的函数值返回的结果:

func Execute(a, b float64, op func(float64, float64) float64) float64 {
    return op(a, b)
}
Run Code Online (Sandbox Code Playgroud)

让我们看看我们之前的例子:

var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
Run Code Online (Sandbox Code Playgroud)

请注意,当然您可以在创建时使用Short变量声明adder:

adder := CreateAdder() // adder is of type: func(float64, float64) float64
Run Code Online (Sandbox Code Playgroud)

Go Playground上试试这些例子.

使用现有功能

当然,如果您已经在具有相同功能类型的包中声明了一个函数,那么您也可以使用它.

例如,math.Mod()具有相同的功能类型:

func Mod(x, y float64) float64
Run Code Online (Sandbox Code Playgroud)

所以你可以将这个值传递给我们的Execute()函数:

fmt.Println(Execute(12, 10, math.Mod)) // Prints 2
Run Code Online (Sandbox Code Playgroud)

打印2因为12 mod 10 = 2.请注意,现有函数的名称充当函数值.

Go Playground尝试一下.

注意:

请注意,参数名称不是类型的一部分,具有相同参数和结果类型的2个函数的类型无论参数的名称如何都是相同的.但要知道,在参数或结果列表中,名称必须全部存在或全部不存在.

所以例如你也可以写:

func CreateAdder() func(P float64, Q float64) float64 {
    return func(x, y float64) float64 {
        return x + y
    }
}
Run Code Online (Sandbox Code Playgroud)

要么:

var adder func(x1, x2 float64) float64 = CreateAdder()
Run Code Online (Sandbox Code Playgroud)