Чи можна передавати функції як параметри?


158

У Java я можу зробити щось на кшталт

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

та "запустити" код у методі пізніше. Біль впоратися (анонімний внутрішній клас), але це можна зробити.

Чи є у Go щось, що може полегшити передачу функції / зворотного виклику як параметр?


7
Nit / уточнення для читачів: У Java "функції" не є прохідними (насправді всі "функції" на Java більш влучно називаються Методами). Виконувані (і анонімні внутрішні класи, що випливають з цього) - це лише те: тип, з якого об'єкти ідентифікуються, які підписалися на необхідний інтерфейс ..

2
(Шість років потому ...) У Java зараз є спосіб передавати методи (наприклад containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

Відповіді:


225

Так, розглянемо кілька таких прикладів:

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

Гра: http://play.golang.org/p/XNMtrDUDS0

Тур: https://tour.golang.org/moretypes/25 (функціональне закриття)


Чи можна передати параметр функції, яка сама є також параметром? У наведених вище прикладах речі, що друкуються, були жорстко закодовані: Друк 123. Чи можуть бути внесені будь-які зміни, щоб ми могли надрукувати щось інше, а не 123? Без оголошення глобальних змінних.
Saty

1
Якщо я правильно розумію ваше запитання, я думаю, що ви шукаєте функцію, яка повертає функцію, дивіться тут, де я замінюю жорстко закодовану функцію "quo123" функцією "цитата", яка досягає того ж результату після того, як ви передасте їй деякий вклад: play.golang.org/p/52ahWAI2xsG
dskinner

34

Ви можете передати функцію як параметр функції Go. Ось приклад передачі функції як параметра іншій функції 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)
}

Ви можете спробувати це за адресою: https://play.golang.org/p/9mAOUWGp0k


2
Дякую! Це був дійсно зрозумілий приклад того, як найкраще використовувати цю ідею! Я відтворив його за допомогою таблиці пошуку структур, які зберігають інформацію, включаючи вказівник на функцію, яку ви хочете виконати. Ідеально підходить для цього!
Джеймс О'Туул

15

Ось зразок реалізації "Мапи" в Go. Сподіваюся, це допомагає !!

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

Ось простий приклад:

    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
це повернення функції, яка не передає функцію
Джон LaBarge

2

Я сподіваюсь, що наведений нижче приклад надасть більше ясності.

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

Так, Go приймає першокласні функції.

Дивіться статтю "Функції першого класу в роботі" про корисні посилання.


4
Будь ласка, розгорніть цю відповідь; включіть приклад, посилання на посилання (наприклад, фактичне посилання) тощо

3
насправді на цій сторінці є 0 інформації, лише посилання на дурний приклад за вихідним кодом.
OZ_
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.