¿Se pueden pasar las funciones como parámetros?

158

En Java puedo hacer algo como

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

y "ejecutar" el código en el método más adelante. Es difícil de manejar (clase interna anónima), pero se puede hacer.

¿Go tiene algo que pueda facilitar que una función / devolución de llamada se pase como parámetro?

Saad
fuente
77
Nit / clarificación para lectores: en Java, las "funciones" no son pasables (en realidad, todas las "funciones" en Java se denominan más adecuadamente Métodos). Ejecutable (y las clases internas anónimas que se derivan de eso) son solo eso: un tipo del que se instancian los objetos que se suscribieron a la interfaz requerida ..
2
(Seis años después ...) Java ahora tiene una forma de pasar métodos (por ejemplo containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Respuestas:

226

Sí, considere algunos de estos ejemplos:

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 "" })
}

Reproducir: http://play.golang.org/p/XNMtrDUDS0

Recorrido: https://tour.golang.org/moretypes/25 (cierres de funciones)

dskinner
fuente
¿Es posible pasar un parámetro a una función que también es un parámetro? En los ejemplos anteriores, las cosas que se imprimen estaban codificadas: Impresión 123. ¿Se pueden realizar cambios para que podamos imprimir algo más que 123? Sin declarar variables globales.
Sábado
1
Si entiendo su pregunta correctamente, creo que está buscando un func que devuelva un func, vea aquí donde reemplazo una función "quote123" codificada por una función "quote" que logra el mismo resultado después de pasarle alguna entrada: play.golang.org/p/52ahWAI2xsG
dskinner
34

Puede pasar la función como parámetro a una función Go. Aquí hay un ejemplo de pasar la función como parámetro a otra función 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)
}

Puede probar esto en: https://play.golang.org/p/9mAOUWGp0k

SeattleOrBayArea
fuente
2
¡Gracias! ¡Este fue un ejemplo muy claro de cómo usar mejor esta idea! Lo he recreado utilizando una tabla de búsqueda de estructuras que almacenan información, incluido un puntero a la función que desea ejecutar. Perfecto para esto!
James O'Toole
15

Aquí está la implementación de "Mapa" de muestra en Go. ¡¡Espero que esto ayude!!

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)

}
robus gauli
fuente
8

Aquí hay un ejemplo simple:

    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))
    }
foamdino
fuente
44
eso devuelve una función que no pasa una función
John LaBarge
2

Espero que el siguiente ejemplo proporcione más claridad.

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
    }})
}
CodeAdocate
fuente
-2

Sí Go acepta funciones de primera clase.

Consulte el artículo "Funciones de primera clase en Go" para obtener enlaces útiles.

AbdulFattah Popoola
fuente
44
Por favor, amplíe esta respuesta algunos; incluir un ejemplo, enlace a la referencia (por ejemplo, referencia real), etc.
3
en realidad hay 0 información en esa página, solo enlace a un ejemplo estúpido por código fuente.
OZ_