函数可以作为参数传递吗?


157

在Java中,我可以做类似的事情

derp(new Runnable { public void run () { /* run this sometime later */ } })

然后稍后在方法中“运行”代码。处理(匿名内部类)很痛苦,但是可以做到。

Go是否有可以促进函数/回调作为参数传递的内容?


7
读者的澄清/澄清:在Java中,“函数”不可传递(实际上,Java中的所有“函数”更恰当地称为“方法”)。可运行的(以及从中派生的匿名内部类)就是这样:一种实例化对象的类型,该对象订阅了所需的接口..

2
(六年后...)Java没有现在有办法通过方法(例如containingObject::instanceMethodName):docs.oracle.com/javase/tutorial/java/javaOO/...
vazor

Answers:


224

是的,请考虑以下示例:

package main

import "fmt"

// convert types take an int and return a string value.
type convert func(int) string

// value implements convert, returning x as string.
func value(x int) string {
    return fmt.Sprintf("%v", x)
}

// quote123 passes 123 to convert func and returns quoted string.
func quote123(fn convert) string {
    return fmt.Sprintf("%q", fn(123))
}

func main() {
    var result string

    result = value(123)
    fmt.Println(result)
    // Output: 123

    result = quote123(value)
    fmt.Println(result)
    // Output: "123"

    result = quote123(func(x int) string { return fmt.Sprintf("%b", x) })
    fmt.Println(result)
    // Output: "1111011"

    foo := func(x int) string { return "foo" }
    result = quote123(foo)
    fmt.Println(result)
    // Output: "foo"

    _ = convert(foo) // confirm foo satisfies convert at runtime

    // fails due to argument type
    // _ = convert(func(x float64) string { return "" })
}

播放:http//play.golang.org/p/XNMtrDUDS0

导览:https : //tour.golang.org/moretypes/25(函数闭包)


是否可以将参数传递给本身也是参数的函数?在上面的示例中,要打印的内容是硬编码的:打印123.是否可以进行任何更改,以便我们可以打印其他内容而不是123?无需声明全局变量。
萨蒂

1
如果我正确理解了您的问题,那么我认为您正在寻找一个返回一个函子的函子,请参见此处,在这里我将一个硬编码的“ quote123”函数替换为一个“ quote”函数,该函数在传递一些输入后会达到相同的结果:play.golang.org/p/52ahWAI2xsG
dskinner

34

您可以将函数作为参数传递给Go函数。这是将函数作为参数传递给另一个Go函数的示例:

package main

import "fmt"

type fn func(int) 

func myfn1(i int) {
    fmt.Printf("\ni is %v", i)
}
func myfn2(i int) {
    fmt.Printf("\ni is %v", i)
}
func test(f fn, val int) {
    f(val)
}
func main() {
    test(myfn1, 123)
    test(myfn2, 321)
}

您可以在以下位置尝试一下:https : //play.golang.org/p/9mAOUWGp0k


1
谢谢!这是如何最好地利用这个想法的一个非常明显的例子!我使用存储信息的结构的查找表(包括指向您要执行的函数的指针)重新创建了它。完美的!
James O'Toole

14

这是Go中的示例“地图”实现。希望这可以帮助!!

func square(num int) int {
    return num * num
}

func mapper(f func(int) int, alist []int) []int {
    var a = make([]int, len(alist), len(alist))
    for index, val := range alist {

        a[index] = f(val)
    }
    return a
}

func main() {
    alist := []int{4, 5, 6, 7}
    result := mapper(square, alist)
    fmt.Println(result)

}

8

这是一个简单的示例:

    package main

    import "fmt"

    func plusTwo() (func(v int) (int)) {
        return func(v int) (int) {
            return v+2
        }
    }

    func plusX(x int) (func(v int) (int)) {
       return func(v int) (int) {
           return v+x
       }
    }

    func main() {
        p := plusTwo()
        fmt.Printf("3+2: %d\n", p(3))

        px := plusX(3)
        fmt.Printf("3+3: %d\n", px(3))
    }

4
返回的函数未传递函数
John LaBarge

2

我希望下面的示例可以使您更加清楚。

package main

type EmployeeManager struct{
    category            string
    city                string
    calculateSalary     func() int64
}


func NewEmployeeManager() (*EmployeeManager,error){

    return &EmployeeManager{
        category : "MANAGEMENT",
        city : "NY",
        calculateSalary: func() int64 {
            var calculatedSalary int64
            // some formula
            return calculatedSalary
        },
    },nil
}

func (self *EmployeeManager) emWithSalaryCalculation(){
    self.calculateSalary = func() int64 {
        var calculatedSalary int64
        // some new formula
        return calculatedSalary
    }
}

func updateEmployeeInfo(em EmployeeManager){
    // Some code
}

func processEmployee(){
    updateEmployeeInfo(struct {
        category        string
        city            string
        calculateSalary func() int64
    }{category: "", city: "", calculateSalary: func() int64 {
        var calculatedSalary int64
        // some new formula
        return calculatedSalary
    }})
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.