Können Funktionen als Parameter übergeben werden?

157

In Java kann ich so etwas machen

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

und "führen" Sie den Code in der Methode später aus. Es ist ein Schmerz zu behandeln (anonyme innere Klasse), aber es kann getan werden.

Hat Go etwas, das die Übergabe einer Funktion / eines Rückrufs als Parameter erleichtern kann?

Saad
quelle
7
Nit / Klarstellung für Leser: In Java sind "Funktionen" nicht passierbar (tatsächlich werden alle "Funktionen" in Java treffender als Methoden bezeichnet). Runnable (und anonyme innere Klassen, die sich daraus ableiten) sind genau das: ein Typ, von dem Objekte instanziiert werden, die die erforderliche Schnittstelle abonniert haben.
2
(Sechs Jahre später ...) Java hat jetzt eine Möglichkeit, Methoden zu übergeben (z. B. containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Antworten:

224

Ja, betrachten Sie einige dieser Beispiele:

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

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

Tour: https://tour.golang.org/moretypes/25 (Funktionsschließungen)

dskinner
quelle
Ist es möglich, einen Parameter an eine Funktion zu übergeben, die selbst auch ein Parameter ist? In den obigen Beispielen waren die Dinge, die gedruckt wurden, fest codiert: Drucken 123. Können Änderungen vorgenommen werden, damit wir etwas anderes als 123 drucken können? Ohne globale Variablen zu deklarieren.
user6205738
1
Wenn ich Ihre Frage richtig verstehe, suchen Sie nach einer Funktion, die eine Funktion zurückgibt. Hier ersetze ich eine fest codierte Funktion "quote123" durch eine Funktion "quote", die das gleiche Ergebnis erzielt, nachdem Sie eine Eingabe übergeben haben: play.golang.org/p/52ahWAI2xsG
dskinner
34

Sie können die Funktion als Parameter an eine Go-Funktion übergeben. Hier ist ein Beispiel für die Übergabe einer Funktion als Parameter an eine andere Go-Funktion:

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

Sie können dies unter folgender Adresse ausprobieren: https://play.golang.org/p/9mAOUWGp0k

SeattleOrBayArea
quelle
1
Danke dir! Dies war ein wirklich klares Beispiel dafür, wie man diese Idee am besten nutzt! Ich habe es mithilfe einer Nachschlagetabelle von Strukturen neu erstellt, in denen Informationen gespeichert sind, einschließlich eines Zeigers auf die Funktion, die Sie ausführen möchten. Perfekt dafür!
James O'Toole
14

Hier ist die Beispielimplementierung "Map" in Go. Hoffe das hilft!!

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
quelle
8

Hier ist ein einfaches Beispiel:

    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
quelle
4
das gibt eine Funktion zurück, die keine Funktion übergibt
John LaBarge
2

Ich hoffe, dass das folgende Beispiel mehr Klarheit bietet.

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
quelle
-2

Yes Go akzeptiert erstklassige Funktionen.

Nützliche Links finden Sie im Artikel "First Class Functions in Go" .

AbdulFattah Popoola
quelle
4
Bitte erweitern Sie diese Antwort einige;
3
Tatsächlich gibt es auf dieser Seite 0 Informationen, die nur per Quellcode auf ein dummes Beispiel verweisen.
OZ_