Heim  >  Artikel  >  Backend-Entwicklung  >  Einführung in Funktionen und Methoden in der Go-Sprache

Einführung in Funktionen und Methoden in der Go-Sprache

尚
nach vorne
2020-01-06 17:51:362649Durchsuche

Einführung in Funktionen und Methoden in der Go-Sprache

Wenn Sie auf eine Funktionsdeklaration ohne Funktionskörper stoßen, bedeutet dies, dass die Funktion nicht in Go implementiert ist.

package math
func Sin(x float64) float //implemented in assembly language

Wenn für jeden Rückgabewert einer Funktion ein Variablenname festgelegt wird, wird dieser mit dem entsprechenden Nullwert initialisiert und der Operand wird in der Rückgabeanweisung der Funktion weggelassen. Diese Verwendung wird als bare bezeichnet zurückkehren.

Bei der Fehlerbehandlung in go wird üblicherweise zuerst eine Reihe von Initialisierungsprüfungen durchgeführt, wobei zuerst der Code verarbeitet wird, der die Fehlerlogik verarbeitet, und dann die eigentliche Logik der Funktion. Dadurch wird der Code prägnanter und vermeidet zu viel Hierarchie.

Beim Definieren einer Funktion können Sie den Funktionstyp als Parameter oder als Rückgabetyp verwenden, um den Abschluss zu implementieren. Es gibt auch anonyme Funktionen, die Lambda-Ausdrücken ähneln. Die strings.Map-Funktion kann zum Experimentieren verwendet werden.

func squares() func() int {
    var x int
    return func() int {
        x++
        return x * x
    }
}
func main() {
    f := squares()
    fmt.Println(f()) // "1"
    fmt.Println(f()) // "4"
    fmt.Println(f()) // "9"
    fmt.Println(f()) // "16"
}

Es gibt Variablenreferenzen in anonymen Funktionen und Quadraten. Aus diesem Grund sind Funktionswerte Referenztypen und Funktionswerte nicht vergleichbar. Go verwendet die Verschlusstechnologie, um Funktionswerte zu implementieren, und Go-Programmierer nennen Funktionswerte auch Schließungen.

Achten Sie auf das Beispielprogramm im Abschnitt „Anonyme Funktionen“ der Golang-Bibel.

Die variable Parameterfunktion der Go-Sprache ist sehr einfach zu verwenden. Sie können mehrere Parameter desselben Typs übergeben oder einen Abschnitt dieses Typs direkt übergeben (beachten Sie, dass Sie die .. Ich denke, es dient dazu, die gleichen Slice-Parameter zu unterscheiden. Wenn Sie unterschiedliche Arten von Variablenparametern verwenden möchten, verwenden Sie die universelle Schnittstelle {} Analysieren Sie einfach die variablen Parameter im Funktionskörper wie ein Slice.

Die Funktion nach dem Defer wird erst dann ausgeführt, wenn die Funktion mit der Defer-Anweisung ausgeführt wird, unabhängig davon, ob die Funktion mit der Defer-Anweisung normal durch Return endet oder aufgrund einer Panik abnormal endet. Sie können mehrere Defer-Anweisungen in einer Funktion ausführen, und ihre Ausführungsreihenfolge ist entgegengesetzt zur Deklarationsreihenfolge

var mu sync.Mutex
var m = make(map[string]int)
func lookup(key string) int {
    mu.Lock()
    defer mu.Unlock()
    return m[key]
}

Beim Debuggen komplexer Programme wird der Defer-Mechanismus häufig auch verwendet, um aufzuzeichnen, wann eine Funktion aufgerufen und beendet werden muss.

func bigSlowOperation() {
    defer trace("bigSlowOperation")() // don't forget the
    extra parentheses
    // ...lots of work…
    time.Sleep(10 * time.Second) // simulate slow
    operation by sleeping
}
func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() { 
        log.Printf("exit %s (%s)", msg,time.Since(start)) 
    }
}

Wir müssen nur zuerst den Rückgabewert von double benennen und dann eine Defer-Anweisung hinzufügen. Wir können die Parameter und den Rückgabewert jedes Mal ausgeben, wenn double aufgerufen wird.

func double(x int) (result int) {
    defer func() { fmt.Printf("double(%d) = %d\n", x,result) }()
    return x + x
}
_ = double(4)
// Output:
// "double(4) = 8"

Um die Problemdiagnose zu erleichtern, ermöglicht das Laufzeitpaket Programmierern die Ausgabe von Stack-Informationen. Im folgenden Beispiel geben wir Stapelinformationen aus, indem wir den Aufruf von printStack in der Hauptfunktion verzögern.

gopl.io/ch5/defer2
func main() {
    defer printStack()
    f(3)
}
func printStack() {
    var buf [4096]byte
    n := runtime.Stack(buf[:], false)
    os.Stdout.Write(buf[:n])
}

Sie können für eine Struktur keine Feldnamen und Methodennamen mit demselben Namen definieren, was etwas seltsam ist.

Funktionszeiger: Es gibt tatsächlich Funktionszeiger in go. Verwenden wir die Go-Sprache, um den tabellengesteuerten Modus zu implementieren.

package main

import (
    "fmt"
)

func add(a int, b int) int {
    return a + b 
}

func sub(a int, b int) int {
    return a - b 
}

func main() {
    fm := make(map[int]func(int, int) int)
    fm[1001] = add 
    fm[1002] = sub 
    protocol := 2001
    i := 1
    j := 2
    if func_handle, ok := fm[protocol]; ok {
        println(func_handle(i, j)) 
    } else {
        fmt.Printf("protocol: %d not register!", protocol)
    }   
}

Lokalen Variablenzeiger zurückgeben:

Im Gegensatz zur C-Sprache können GO-Funktionen lokale Änderungszeiger zurückgeben, und der Compiler verwendet die Escape-Analyse, um zu entscheiden, ob Speicher auf dem Heap zugewiesen werden soll.

Sie können das Funktions-Inlining über den Parameter -gcflags „-l -m“ beim Kompilieren deaktivieren. Das hat einige Auswirkungen auf die Speicherzuweisung, die Details sind jedoch unklar.

Es gibt keine sogenannte Referenzübergabe von Funktionsparametern, sie werden alle als Wert übergeben. Der Unterschied besteht nur darin, ob das kopierte Objekt oder der Zeiger übergeben wird. In der C-Sprache wird im Allgemeinen empfohlen, Zeigerparameter zu übergeben, um das Kopieren von Objekten zu vermeiden und die Effizienz zu verbessern.

Aber in Go verlängert der kopierte Zeiger den Lebenszyklus des Zielobjekts und kann auch dazu führen, dass es auf dem Heap zugewiesen wird, sodass der Leistungsverbrauch zu den Kosten für die Heap-Speicherzuweisung hinzukommt und Garbage Collection, während in go Das Kopieren kleiner Objekte auf den Stapel erfolgt tatsächlich sehr schnell. Wenn das Objekt also nicht besonders groß ist oder das Originalobjekt wirklich geändert werden muss, besteht im Allgemeinen keine Notwendigkeit, Zeigerparameter zu übergeben. Bei der gleichzeitigen Programmierung wird auch die Verwendung unveränderlicher Objekte (schreibgeschützt oder kopiert) empfohlen, wodurch die Probleme der Datensynchronisierung beseitigt werden können.

Das Folgende wird Speicher auf dem Heap zuweisen. Übergeben Sie beim Kompilieren -gcflags „-m“, um den Assembler-Code anzuzeigen:

func test(p *int) {
    go func() {
        println(p)
    }() 
}

func main() {
    x := 100 
    p := &x
    test(p)
}

Verwenden Sie ausgehende Parameter. Es wird empfohlen, den Rückgabewert zu verwenden Sie können auch zwei Level-Zeiger verwenden:

func test(p **int) {
    x := 100
    *p = &x
}

func main() {
    var p *int
    test(&p)
    println(*p)
}

Für weitere Go-Sprachkenntnisse beachten Sie bitte die Spalte Go-Sprach-Tutorial auf der chinesischen PHP-Website.

Das obige ist der detaillierte Inhalt vonEinführung in Funktionen und Methoden in der Go-Sprache. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen