Je viens de JavaScript qui a un support de fonction de première classe. Par exemple, vous pouvez:
Quelqu'un peut-il me donner un exemple de la façon dont je procéderais dans Go?
Go Programmation fonctionnelle et linguistique pourrait vous aider. De cet article de blog:
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());
}
L'auteur est le propriétaire du blog: Dethe Elza (pas moi)
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)
}
sortie:
222111
222111
La section correspondante de la spécification: Types de fonction .
Toutes les autres réponses ici déclarent d’abord un nouveau type, ce qui est une bonne pratique et facilite la lecture de votre code, mais sachez que ce n’est pas une obligation.
Vous pouvez utiliser des valeurs de fonction sans déclarer un nouveau type pour elles, comme illustré dans l'exemple ci-dessous.
Déclarer une variable de type fonction qui a 2 paramètres de type float64
et une valeur de retour de type float64
ressemble à ceci:
// Create a var of the mentioned function type:
var f func(float64, float64) float64
Écrivons une fonction qui retourne une fonction d'addition. Cette fonction additionneur doit prendre 2 paramètres de type float64
et doit renvoyer la somme de ces 2 nombres lorsqu'elle est appelée:
func CreateAdder() func(float64, float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
Écrivons une fonction qui a 3 paramètres, les 2 premiers étant du type float64
, et le 3ème étant une valeur de fonction, une fonction prenant 2 paramètres d'entrée de type float64
et produisant une valeur de type float64
. Et la fonction que nous écrivons appellera la valeur de la fonction qui lui est transmise en tant que paramètre. Elle utilisera les 2 premières valeurs float64
comme arguments pour la valeur de la fonction et renverra le résultat renvoyé par la valeur de la fonction transmise:
func Execute(a, b float64, op func(float64, float64) float64) float64 {
return op(a, b)
}
Voyons nos exemples précédents en action:
var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
Notez bien sûr que vous pouvez utiliser la déclaration Variable courte lors de la création de adder
:
adder := CreateAdder() // adder is of type: func(float64, float64) float64
Essayez ces exemples sur le Go Playground .
Bien sûr, si vous avez déjà une fonction déclarée dans un package avec le même type de fonction, vous pouvez également l'utiliser.
Par exemple, math.Mod()
a le même type de fonction:
func Mod(x, y float64) float64
Vous pouvez donc transmettre cette valeur à notre fonction Execute()
:
fmt.Println(Execute(12, 10, math.Mod)) // Prints 2
Imprime 2
car 12 mod 10 = 2
. Notez que le nom d'une fonction existante agit comme une valeur de fonction.
Essayez-le sur le Go Playground .
Remarque:
Notez que les noms de paramètre ne font pas partie du type, le type de 2 fonctions ayant le même paramètre et le même type de résultat est identique quel que soit le nom du paramètre. Mais sachez que dans une liste de paramètres ou de résultats, les noms doivent tous être présents ou tous absents.
Ainsi, par exemple, vous pouvez également écrire:
func CreateAdder() func(P float64, Q float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
Ou:
var adder func(x1, x2 float64) float64 = CreateAdder()
Bien que vous puissiez utiliser une variable ou déclarer un type, vous n'avez pas besoin de . Vous pouvez le faire tout simplement:
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
Juste un casse-tête avec une définition de fonction récursive pour chaîner les middlewares dans une application Web.
Tout d'abord, la boîte à outils:
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
)
Comme vous le voyez, le type Chain
est une fonction qui retourne une autre fonction du même type Chain
(Comment est la première classe!!).
Maintenant quelques tests pour le voir en action:
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
Encore une fois, c’était là un casse-tête pour montrer que nous pouvons utiliser des fonctions de première classe dans Go de différentes manières. Personnellement, j'utilise chi de nos jours en tant que routeur et pour le traitement des middlewares.