2015-02-17 15 views
7

Dlaczego nie można zdefiniować funkcji rekursywnej jako zmiennej? Wydaje mi się, że potrafię definiować dowolne funkcje, z wyjątkiem przypadków, gdy się powtarzają.Funkcja i funkcja zmiennych funkcji gambang

Jest to prawna:

func f(i int) int { 
    if i == 0 { 
     return 1 
    } 
    return i * f(i-1) 
} 

func main() { 
    fmt.Println(f(2)) 
} 

To jest nielegalne:

var f func(int) int = func(i int) int { 
    if i == 0 { 
     return 1 
    } 
    return i * f(i-1) 
} 

func main() { 
    fmt.Println(f(2)) 
} 

To jest legalne i zgaduję, że to tylko dlatego, że można dowiedzieć się, f po inicjalizacji:

func main() { 
    var f *func(int) int; 
    t := func(i int) int { 
     if i == 0 { 
      return 1 
     } 
     return i * (*f)(i-1) 
    } 
    f = &t 
    fmt.Println((*f)(2)) 
} 

Wygląda więc na to, że sprowadza się do funkcji, a deklaracje zmiennych typu funkcji są traktowane jako różne. ale z lektury dokumentacji nie spodziewałbym się, że tak będzie. Czy brakowało mi części dokumentacji opisującej to?

Oczekuję, że nielegalna sprawa zadziała, ponieważ działa w innych językach. Podobnie jak w JavaScript:

(function() { 
    var f = function (i) { 
    if (i == 0) { 
     return 1; 
    } 
    return i * f(i - 1); 
    }; 

    console.log(f(2)); 
})(); 
+3

Go nie Javascript. Javascript sprawdza twój kod i mówi "że wygląda dobrze, nie wiem co to jest" f ", ale prawdopodobnie do czasu, kiedy ten blok zostanie wywołany", a następnie przypisze funkcję do zmiennej 'f', i Wszystko jest dobrze. Go chce wiedzieć, co 'f' jest pierwsze, zanim napotka kod, który go wywołuje. –

+0

To właśnie się dzieje, ale tak naprawdę nie wyjaśnia dlaczego. Go nie chce wiedzieć, co 'f' jest, jeśli' f' jest zadeklarowane jako funkcja, ale Go chce wiedzieć, czy 'f' jest zadeklarowane jako zmienna typu funkcji. To jest dziwne. –

Odpowiedz

21

Poniższy kod byłby preferowanym sposobem robienia tego, co opisujesz. Należy pamiętać, że nie trzeba utworzyć dodatkową zmienną, ani nie masz wskaźnik do funkcji:

package main 

import "fmt" 

func main() { 
    var f func(int) int 
    f = func(i int) int { 
     if i == 0 { 
      return 1 
     } 
     return i * f(i-1) 
    } 
    fmt.Println(f(2)) 
} 
+0

Dzięki temu o wiele lepiej działające rozwiązanie. Mam nadzieję na jakąś dokumentację, która to wskazuje. Wydaje się dziwne, że funkcje i zmienne typów funkcji są traktowane tak różnie. –

+2

@DanielWilliams: Z [spec] (https://golang.org/ref/spec#Declarations_and_scope): * Zakres stałego lub zmiennego identyfikatora zadeklarowanego w funkcji zaczyna się na końcu ConstSpec lub VarSpec (ShortVarDecl for krótkie deklaracje zmiennych) i kończy się na końcu najbardziej wewnętrznego bloku zawierającego. * Oznacza to, że identyfikator 'f' nie jest ważny, dopóki wartość nie zostanie w pełni zdefiniowana. Dlatego nie można robić w Go, co robisz w JavaScript. –