As funções podem ser passadas como parâmetros?

157

Em Java eu ​​posso fazer algo como

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

e "execute" o código no método posteriormente. É difícil lidar (classe interna anônima), mas pode ser feito.

O Go tem algo que pode facilitar a passagem de uma função / retorno de chamada como parâmetro?

Saad
fonte
7
Aviso / esclarecimento para os leitores: Em Java, "funções" não são passáveis ​​(na verdade, todas as "funções" em Java são mais apropriadamente chamadas de Métodos). Runnable (e classes internas anônimas que derivam do que) são apenas isso: um tipo a partir do qual os objetos são instanciado que subscreveram a interface necessária ..
2
(Seis anos depois ...) Java agora tem uma maneira de passar métodos (por exemplo containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Respostas:

224

Sim, considere alguns destes exemplos:

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

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

Tour: https://tour.golang.org/moretypes/25 (fechamentos de funções)

dskinner
fonte
É possível passar um parâmetro para uma função que também é um parâmetro? Nos exemplos acima, as coisas impressas foram codificadas: Impressão 123. Podem ser feitas alterações para que possamos imprimir algo mais do que 123? Sem declarar variáveis ​​globais.
Saty
1
Se entendi sua pergunta corretamente, acho que você está procurando uma função que retorne uma função. Consulte aqui onde eu substituo uma função "quote123" codificada por uma função "quote" que obtém o mesmo resultado depois de passar alguma entrada: play.golang.org/p/52ahWAI2xsG
dskinner 02/04/19
34

Você pode passar a função como parâmetro para uma função Ir. Aqui está um exemplo de passar a função como parâmetro para outra função 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)
}

Você pode tentar isso em: https://play.golang.org/p/9mAOUWGp0k

SeattleOrBayArea
fonte
1
Obrigado! Este foi um exemplo muito claro de como melhor usar essa idéia! Eu o recriei usando uma tabela de pesquisa de estruturas que armazenam informações, incluindo um ponteiro para a função que você deseja executar. Perfeito para isso!
James O'Toole
14

Aqui está a implementação "Mapa" de exemplo no Go. Espero que isto ajude!!

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

Aqui está um exemplo simples:

    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
fonte
4
que está retornando uma função não passando de uma função
John LaBarge
2

Espero que o exemplo abaixo forneça mais clareza.

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

O Yes Go aceita funções de primeira classe.

Consulte o artigo "Funções de primeira classe no Go" para obter links úteis.

AbdulFattah Popoola
fonte
4
Por favor, expanda nesta resposta alguns; inclua um exemplo, link para referência (por exemplo, referência real), etc.
3
na verdade, existem 0 informações nessa página, apenas link para exemplo estúpido por código fonte.
OZ_