Czy funkcje można przekazywać jako parametry?


158

W Javie mogę zrobić coś takiego

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

i „uruchom” kod w metodzie później. Trudno sobie z tym poradzić (anonimowa klasa wewnętrzna), ale można to zrobić.

Czy Go ma coś, co może ułatwić przekazywanie funkcji / wywołania zwrotnego jako parametru?


7
Nit / wyjaśnienie dla czytelników: w Javie „funkcje” są niedopuszczalne (właściwie wszystkie „funkcje” w Javie są trafniej nazywane metodami). Runnable (i anonimowe klasy wewnętrzne, które z tego pochodzą) to po prostu: typ, z którego tworzone są instancje obiektów, który subskrybował wymagany interfejs ..

2
(Sześć lat później ...) Java ma teraz sposób na przekazywanie metod (np. containingObject::instanceMethodName): Docs.oracle.com/javase/tutorial/java/javaOO/ ...
vazor

Odpowiedzi:


225

Tak, rozważ kilka z tych przykładów:

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

Odtwórz: http://play.golang.org/p/XNMtrDUDS0

Wycieczka: https://tour.golang.org/moretypes/25 (Zamknięcia funkcji)


Czy można przekazać parametr do funkcji, która sama jest również parametrem? W powyższych przykładach drukowane rzeczy były zakodowane na stałe: Drukowanie 123. Czy można wprowadzić jakieś zmiany, abyśmy mogli wydrukować coś innego niż 123? Bez deklarowania zmiennych globalnych.
Saty

1
Jeśli dobrze rozumiem twoje pytanie, myślę, że szukasz funkcji, która zwraca func, zobacz tutaj, gdzie zastępuję zakodowaną na stałe funkcję „quote123” funkcją „quote”, która osiąga ten sam wynik po przekazaniu jej pewnych danych wejściowych: play.golang.org/p/52ahWAI2xsG
dskinner

34

Funkcję można przekazać jako parametr do funkcji Go. Oto przykład przekazywania funkcji jako parametru do innej funkcji 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)
}

Możesz to wypróbować na: https://play.golang.org/p/9mAOUWGp0k


2
Dziękuję Ci! To był naprawdę jasny przykład tego, jak najlepiej wykorzystać ten pomysł! Odtworzyłem go przy użyciu tabeli przeglądowej struktur, które przechowują informacje, w tym wskaźnik do funkcji, którą chcesz wykonać. Idealne do tego!
James O'Toole

15

Oto przykładowa implementacja „Mapy” w Go. Mam nadzieję że to pomoże!!

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

Oto prosty przykład:

    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
to zwraca funkcję, która nie przekazuje funkcji
John LaBarge

2

Mam nadzieję, że poniższy przykład zapewni większą jasność.

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

Tak, Go akceptuje pierwszorzędne funkcje.

Przydatne linki można znaleźć w artykule „Funkcje pierwszej klasy w ruchu .


4
Proszę rozwinąć tę odpowiedź. zawierać przykład, link do odniesienia (np. rzeczywiste odniesienie) itp.

3
w rzeczywistości na tej stronie jest 0 informacji, tylko link do głupiego przykładu przez kod źródłowy.
OZ_
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.