Les fonctions peuvent-elles être passées en paramètres?

158

En Java, je peux faire quelque chose comme

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

et "exécutez" le code dans la méthode plus tard. C'est difficile à gérer (classe interne anonyme), mais cela peut être fait.

Go a-t-il quelque chose qui peut faciliter la transmission d'une fonction / rappel en tant que paramètre?

Saad
la source
7
Nit / clarification pour les lecteurs: En Java, les «fonctions» ne sont pas passables (en fait, toutes les «fonctions» en Java sont plus justement appelées Méthodes). Runnable (et les classes internes anonymes qui en dérivent) ne sont que cela: un type à partir duquel les objets sont instanciés qui se sont abonnés à l'interface requise ..
2
(Six ans plus tard ...) Java a maintenant un moyen de passer des méthodes (par exemple containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Réponses:

226

Oui, considérez certains de ces exemples:

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

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

Visite: https://tour.golang.org/moretypes/25 (fermetures de fonction)

dskinner
la source
Est-il possible de passer un paramètre à une fonction qui est elle-même aussi un paramètre? Dans les exemples ci-dessus, les éléments à imprimer étaient codés en dur: Impression 123. Des modifications peuvent-elles être apportées pour que nous puissions imprimer autre chose que 123? Sans déclarer de variables globales.
Sam
1
Si je comprends bien votre question, je pense que vous cherchez une func qui renvoie une func, voyez ici où je remplace une fonction "quote123" codée en dur par une fonction "quote" qui obtient le même résultat après lui avoir transmis une entrée: play.golang.org/p/52ahWAI2xsG
dskinner
34

Vous pouvez passer une fonction comme paramètre à une fonction Go. Voici un exemple de passage d'une fonction en tant que paramètre à une autre fonction 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)
}

Vous pouvez essayer ceci sur: https://play.golang.org/p/9mAOUWGp0k

SeattleOrBayArea
la source
2
Je vous remercie! C'était un exemple très clair de la meilleure façon d'utiliser cette idée! Je l'ai recréé en utilisant une table de recherche de structures qui stockent des informations, y compris un pointeur vers la fonction que vous souhaitez exécuter. Parfait pour ça!
James O'Toole
15

Voici l'exemple d'implémentation "Map" dans Go. J'espère que cela t'aides!!

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
la source
8

Voici un exemple 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
la source
4
qui renvoie une fonction ne passant pas une fonction
John LaBarge
2

J'espère que l'exemple ci-dessous apportera plus de clarté.

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
la source
-2

Yes Go accepte les fonctions de première classe.

Consultez l'article «Fonctions de première classe dans Go» pour des liens utiles.

AbdulFattah Popoola
la source
4
Veuillez développer cette réponse un peu; inclure un exemple, un lien vers une référence (par exemple une référence réelle), etc.
3
en fait, il y a 0 information sur cette page, seulement un lien vers un exemple stupide par code source.
OZ_