Le funzioni possono essere passate come parametri?


158

In Java posso fare qualcosa del genere

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

ed "esegui" il codice nel metodo in un secondo momento. È una seccatura da gestire (classe interna anonima), ma può essere fatto.

Go ha qualcosa che può facilitare il passaggio di una funzione / callback come parametro?


7
Nit / chiarimenti per i lettori: in Java, le "funzioni" non sono passabili (in realtà, tutte le "funzioni" in Java sono più appropriatamente chiamate Metodi). Eseguibili (e classi interne anonime che ne derivano) sono proprio questo: un tipo da cui vengono istanziati gli oggetti che si sono abbonati all'interfaccia richiesta.

2
(Sei anni dopo ...) Java ora ha un modo per passare metodi (ad es. containingObject::instanceMethodName): Docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Risposte:


226

Sì, considera alcuni di questi esempi:

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

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

Tour: https://tour.golang.org/moretypes/25 (Function Closures)


È possibile passare un parametro a una funzione che è anch'essa un parametro? Negli esempi precedenti, le cose che vengono stampate sono state codificate: Stampa 123. È possibile apportare modifiche in modo da poter stampare qualcos'altro anziché 123? Senza dichiarare le variabili globali.
Saty,

1
Se capisco correttamente la tua domanda, penso che tu stia cercando una funzione che restituisca una funzione, vedi qui dove sostituisco una funzione "quote123" codificata con una funzione "quote" che ottiene lo stesso risultato dopo aver passato alcuni input: play.golang.org/p/52ahWAI2xsG
dskinner

34

È possibile passare la funzione come parametro a una funzione Go. Ecco un esempio di passaggio della funzione come parametro a un'altra funzione 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)
}

Puoi provarlo su: https://play.golang.org/p/9mAOUWGp0k


2
Grazie! Questo è stato un chiaro esempio di come utilizzare al meglio questa idea! L'ho ricreato utilizzando una tabella di ricerca di strutture che memorizzano informazioni, incluso un puntatore alla funzione che si desidera eseguire. Perfetto per questo!
James O'Toole,

15

Ecco l'implementazione "Mappa" di esempio in Go. Spero che questo ti aiuti!!

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

Qui c'è un semplice esempio:

    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
che sta restituendo una funzione che non passa una funzione
John LaBarge

2

Spero che l'esempio che segue fornirà maggiore chiarezza.

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

-2

Sì, Go accetta funzioni di prima classe.

Vedi l'articolo "Funzioni di prima classe in movimento" per link utili.


4
Si prega di espandere su questa risposta alcuni; includere un esempio, collegamento al riferimento (ad esempio riferimento effettivo), ecc.

3
in realtà ci sono 0 informazioni su quella pagina, solo link a stupidi esempi per codice sorgente.
OZ_
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.