2015-02-17 16 views
7

Warum kann ich eine rekursive Funktion nicht als Variable definieren? Ich scheine in der Lage zu sein, beliebige Funktionen zu definieren, außer wenn sie rekrutieren.Golang-Funktion und Funktionsvariable Semantik

Das ist legal:

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

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

Dies ist illegal:

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

Diese legal ist und ich vermute es nur, weil man f nach der Initialisierung herausfinden kann, ist:

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

Es sieht also so aus, als ob Funktion und Variablendeklarationen eines Funktionstyps unterschiedlich behandelt werden Allerdings würde ich aus der Lektüre der Dokumentation nicht erwarten, dass dies der Fall ist. Habe ich den Teil der Dokumentation vermisst, der das genau beschreibt?

Ich würde erwarten, dass der illegale Fall funktioniert, nur weil es in anderen Sprachen funktioniert. Wie in JavaScript:

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

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

Go nicht Javascript ist. Javascript sieht auf Ihren Code und sagt "Das sieht gut aus, ich weiß nicht, was' f' ist noch, aber wahrscheinlich werde ich mit dem Zeitpunkt, wenn dieser Block aufgerufen wird ", und weist dann die Funktion der Variablen' f' zu Alles ist gut. Go möchte zuerst wissen, was "f" ist, bevor es auf Code stößt, der es aufruft. –

+0

Das ist was passiert, sagt aber nicht wirklich warum. Go möchte nicht wissen, was "f" ist, wenn "f" als eine Funktion deklariert ist, aber Go möchte wissen, ob "f" als eine Funktionstypvariable deklariert ist. Das ist seltsam. –

Antwort

21

Der folgende Code wäre die bevorzugte Art zu tun, was Sie beschreiben. Beachten Sie, dass Sie müssen keine zusätzliche Variable erstellen, noch haben Sie einen Zeiger auf eine Funktion:

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

Danke, das ist eine viel bessere Arbeitslösung. Ich hoffe auf eine Dokumentation, die darauf hinweist. Es scheint sehr seltsam zu sein, dass Funktionen und Variablen von Funktionstypen so unterschiedlich behandelt werden. –

+2

@DanielWilliams: Aus der [Spezifikation] (https://golang.org/ref/spec#Declarations_and_scope): * Der Gültigkeitsbereich einer Konstanten- oder Variablen-ID, die in einer Funktion deklariert ist, beginnt am Ende der ConstSpec oder VarSpec (ShortVarDecl für kurze Variablendeklarationen) und endet am Ende des innersten umschließenden Blocks. * Das bedeutet, dass der 'f'identifier nicht gültig ist, bis der Wert vollständig definiert ist. Deshalb können Sie in Go nicht machen, was Sie in JavaScript tun. –