Я исхожу из JavaScript, который поддерживает функцию первого класса. Например, вы можете:
- передать функцию в качестве параметра другой функции
 - возвращает функцию из функции.
 
Может кто-нибудь дать мне пример того, как я буду делать это в Go?
Я исхожу из JavaScript, который поддерживает функцию первого класса. Например, вы можете:
Может кто-нибудь дать мне пример того, как я буду делать это в Go?
Go Language и функциональное программирование могут помочь. Из этого сообщения в блоге:
package main
import fmt "fmt"
type Stringy func() string
func foo() string{
        return "Stringy function"
}
func takesAFunction(foo Stringy){
    fmt.Printf("takesAFunction: %v\n", foo())
}
func returnsAFunction()Stringy{
    return func()string{
        fmt.Printf("Inner stringy function\n");
        return "bar" // have to return a string to be stringy
    }
}
func main(){
    takesAFunction(foo);
    var f Stringy = returnsAFunction();
    f();
    var baz Stringy = func()string{
        return "anonymous stringy\n"
    };
    fmt.Printf(baz());
}
Автор - владелец блога: Dethe Elza (не я)
package main
import (
    "fmt"
)
type Lx func(int) int
func cmb(f, g Lx) Lx {
    return func(x int) int {
        return g(f(x))
    }
}
func inc(x int) int {
    return x + 1
}
func sum(x int) int {
    result := 0
    for i := 0; i < x; i++ {
        result += i
    }
    return result
}
func main() {
    n := 666
    fmt.Println(cmb(inc, sum)(n))
    fmt.Println(n * (n + 1) / 2)
}
выход:
222111
222111
		Связанный раздел из спецификации: Типы функций.
Все остальные ответы здесь сначала объявляют новый тип, который хорош (практика) и делает ваш код более легким для чтения, но знайте, что это не является обязательным требованием.
Вы можете работать со значениями функций без объявления для них нового типа, как показано в приведенном ниже примере.
Объявление переменной типа функции, которая имеет 2 параметра типа float64 и имеет одно возвращаемое значение типа float64, выглядит так:
// Create a var of the mentioned function type:
var f func(float64, float64) float64
Пусть напишет функцию, которая возвращает функцию сумматора. Эта функция сумматора должна принимать 2 параметра типа float64 и должна возвращать сумму этих двух чисел при вызове:
func CreateAdder() func(float64, float64) float64 {
    return func(x, y float64) float64 {
        return x + y
    }
}
Пусть записывается функция, которая имеет 3 параметра, первые 2 имеют тип float64, а 3 - значение функции, функция, которая принимает 2 входных параметра типа float64 и выдает значение типа float64, И функция, которую мы пишем, вызовет значение функции, которое передается ему как параметр, и используя первые 2 float64 значения в качестве аргументов для значения функции и возвращает результат, возвращаемый переданным значением функции:
func Execute(a, b float64, op func(float64, float64) float64) float64 {
    return op(a, b)
}
Посмотрите наши предыдущие примеры в действии:
var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
Обратите внимание, что при создании adder можно использовать объявление коротких переменных:
adder := CreateAdder() // adder is of type: func(float64, float64) float64
Попробуйте эти примеры на Go Playground.
Конечно, если у вас уже есть функция, объявленная в пакете с тем же типом функции, вы также можете использовать это.
Например, math.Mod() имеет тот же тип функции:
func Mod(x, y float64) float64
Итак, вы можете передать это значение нашей функции Execute():
fmt.Println(Execute(12, 10, math.Mod)) // Prints 2
Печать 2, потому что 12 mod 10 = 2. Обратите внимание, что имя существующей функции действует как значение функции.
Попробуйте на Go Playground.
Примечание:
Обратите внимание, что имена параметров не являются частью типа, тип 2 функций, имеющих одинаковый параметр и типы результатов, идентичен независимо от имен параметров. Но знайте, что в списке параметров или результатов имена должны либо присутствовать, либо вообще отсутствовать.
Так, например, вы также можете написать:
func CreateAdder() func(P float64, Q float64) float64 {
    return func(x, y float64) float64 {
        return x + y
    }
}
Или:
var adder func(x1, x2 float64) float64 = CreateAdder()
		Пока вы можете использовать var или declare a type, вам не нужно. Вы можете сделать это довольно просто:
package main
import "fmt"
var count int
func increment(i int) int {
    return i + 1
}
func decrement(i int) int {
    return i - 1
}
func execute(f func(int) int) int {
    return f(count)
}
func main() {
    count = 2
    count = execute(increment)
    fmt.Println(count)
    count = execute(decrement)
    fmt.Println(count)
}
//The output is:
3
2
		Просто аналитик с рекурсивным определением функции для привязки middlewares в веб-приложении.
Во-первых, панель инструментов:
func MakeChain() (Chain, http.Handler) {
    nop := http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {})
    var list []Middleware
    var final http.Handler = nop
    var f Chain
    f = func(m Middleware) Chain {
        if m != nil {
            list = append(list, m)
        } else {
            for i := len(list) - 1; i >= 0; i-- {
                mid := list[i]
                if mid == nil {
                    continue
                }
                if next := mid(final); next != nil {
                    final = next
                } else {
                    final = nop
                }
            }
            if final == nil {
                final = nop
            }
            return nil
        }
        return f
    }
    return f, final
}
type (
    Middleware func(http.Handler) http.Handler
    Chain      func(Middleware) Chain
)
Как вы видите, тип Chain - это функция, которая возвращает другую функцию того же типа Chain (Как первый класс это!).
Теперь несколько тестов, чтобы увидеть это в действии:
func TestDummy(t *testing.T) {
    c, final := MakeChain()
    c(mw1(`OK!`))(mw2(t, `OK!`))(nil)
    log.Println(final)
    w1 := httptest.NewRecorder()
    r1, err := http.NewRequest("GET", "/api/v1", nil)
    if err != nil {
        t.Fatal(err)
    }
    final.ServeHTTP(w1, r1)
}
func mw2(t *testing.T, expectedState string) func(next http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            val := r.Context().Value(contextKey("state"))
            sval := fmt.Sprintf("%v", val)
            assert.Equal(t, sval, expectedState)
        })
    }
}
func mw1(initialState string) func(next http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            ctx := context.WithValue(r.Context(), contextKey("state"), initialState)
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
}
type contextKey string
Опять же, это был просто мотив, чтобы показать, что мы можем использовать функции первого класса в Go по-разному. Лично я использую chi в настоящее время как маршрутизатор и для обработки посредников.