Go (Programmiersprache)

aus Wikipedia, der freien Enzyklopädie
Wechseln zu: Navigation, Suche
Go
Maskottchen von Go
Basisdaten
Paradigmen: nebenläufig, imperativ, strukturiert, modular, objektorientiert
Erscheinungsjahr: 2009; erste stabile Version 2012
Entwickler: Robert Griesemer, Rob Pike, Ken Thompson u.a.
Aktuelle Version: 1.3  (18. Juni 2014)
Typisierung: stark, statisch
Wichtige Implementierungen: Gc, gccgo
Beeinflusst von: C, Newsqueak, Alef, Limbo, Oberon
Betriebssystem: Linux, OS X, FreeBSD, Microsoft Windows, Experimentell: DragonFly BSD, Plan 9, Solaris
Lizenz: BSD-Lizenz
golang.org

Go ist eine kompilierbare Programmiersprache, die Nebenläufigkeit unterstützt und über eine automatische Speicherbereinigung verfügt.

Sie wurde von Mitarbeitern des Unternehmens Google Inc.[1] entwickelt. Die Entwürfe stammen von Robert Griesemer, Rob Pike und Ken Thompson.

Go orientiert sich syntaktisch an der Programmiersprache C mit einigem Einfluss aus der Wirthschen Sprachfamilie (Pascal, Modula und insbesondere Oberon). Die Unterstützung für Nebenläufigkeit wurde nach Vorbild der von Tony Hoare eingeführten Communicating Sequential Processes (CSP) gestaltet und steht in Tradition der Programmiersprachen Newsqueak, Alef und Limbo.[2]

Hintergründe, Entwicklungsziele[Bearbeiten]

Go wurde aus Unzufriedenheit über die bestehenden Sprachen zur Softwareentwicklung wie C++ oder Java im Kontext heutiger Computersysteme, insbesondere im Hinblick auf skalierbare Netzwerkdienste, Cluster- und Cloud-Computing, entwickelt.[3] Wichtige Ziele bei der Entwicklung waren unter anderem die Unterstützung von Nebenläufigkeit mit nativen Sprachelementen und die Erleichterung der Softwareentwicklung mit großen Entwicklerteams und großen Codebasen.[4] Go besitzt einen eigenen Garbage Collector, erlaubt die Verwendung von Zeigern, verzichtet jedoch auf Zeigerarithmetik.[5] Go ist eine kompilierte Sprache, bei der Wert auf eine hohe Übersetzungsgeschwindigkeit gelegt wurde.

Merkmale, Sprachmittel[Bearbeiten]

Go bietet Closures und Reflexion[6] sowie Typsicherheit und eine Garbage Collection. Objektorientierung unterstützt Go durch Interfaces und Mixins. Auf Klassen wird bewusst verzichtet. Außerdem ist es möglich, den Quellcode wie bei Java durch Pakete zu modularisieren. Nebenläufigkeit wird durch Communicating Sequential Processes realisiert, die Goroutinen genannt sind und über Kanäle (Channels) miteinander kommunizieren können. Generische Typen gibt es nicht, eine spätere Integration ist aber nicht ausgeschlossen.[7] Unicode wird in Form von UTF-8 unterstützt, sowohl für Strings als auch für Variablenbezeichner im Quelltext (allerdings nur Unicode-Buchstaben und -Ziffern), „Δt = t1 - t2“ ist also möglich.[8]

Syntax[Bearbeiten]

Die Syntax von Go orientiert sich im Wesentlichen an der Syntax der Programmiersprache C, weicht davon aber an einigen Stellen ab. So kann beispielsweise auf den Abschluss von Anweisungen durch ein Semikolon verzichtet werden. Datentypen werden bei Deklarationen hinter den Bezeichner geschrieben statt davor, um die Deklaration von Funktionstypen zu vereinfachen.[9] Code-Blöcke werden mit geschweiften Klammern abgegrenzt. Neben dem einfachen Gleichheitszeichen als Zuweisungsoperator gibt es zusätzlich den Operator :=, der Deklaration mit Typinferenz und Zuweisung kombiniert. Die Sprache umfasst mit 25 Schlüsselwörtern weniger Schlüsselwörter als ANSI C.

Kommentare werden wie in C oder C++ mit Schrägstrichen markiert; „/*“ bis „*/“ bezeichnet einen Kommentarbereich, der auch mehrere Zeilen beinhalten kann, „//“ leitet einen Kommentarbereich bis zum Ende der Zeile ein.

Jede Quelldatei gehört genau einem Paket an, das am Anfang der Datei mit der „package“-Anweisung angegeben wird.

Das Schlüsselwort für Funktionen lautet „func“, die Funktion „main“ in dem „main“-Paket ist der Startpunkt des Go-Programms.

Jede Variable hat einen definierten Typ.

Einfaches Beispiel mit Textausgabe[Bearbeiten]

package main
 
import "fmt"
 
func main() {
	fmt.Println("Hello, World")
}

Ein weiteres Beispiel berechnet die Kreiszahl Pi näherungsweise über die Leibniz-Reihe. Für die Berechnung werden Goroutinen und Kanäle verwendet:

package main
 
import (
	"fmt"
	"math"
)
 
func main() {
	fmt.Println(calcpi(5000))
}
 
// calcpi startet n Goroutinen um eine
// Näherung von Pi zu berechnen.
func calcpi(n int) float64 {
	ch := make(chan float64)
	for k := 0; k <= n; k++ {
		go term(ch, float64(k))
	}
	f := float64(0.0)
	for k := 0; k <= n; k++ {
		f += <-ch
	}
	return f
}
 
func term(ch chan float64, k float64) {
	ch <- 4 * math.Pow(-1, k) / (2*k + 1)
}

Objektorientierung[Bearbeiten]

Go unterstützt objektorientierte Programmierung, diese ist jedoch nicht klassenbasiert. Datentypen können in Go Methoden besitzen. Polymorphie wird über Interfaces (Schnittstellen) erreicht, über die Methodenaufrufe zur Laufzeit an die konkrete Implementierung gebunden werden (Dynamische Bindung). Für einen Datentyp muss nicht explizit deklariert werden, dass er ein bestimmtes Interface erfüllt. Diese Beziehung wird stattdessen implizit beim Kompilieren ermittelt, um lose Kopplung zu erreichen.

Statt Vererbung und Typ-Hierarchien kommt in Go Komposition zum Einsatz. Hierfür unterstützt Go eine Form von Mixins, die in Go embedding („Einbettung“) genannt wird: eine Datenstruktur kann beliebig viele andere Datentypen einbetten, so dass sie deren Methoden und Datenfelder erhält.

Nebenläufigkeit[Bearbeiten]

Zur Unterstützung der nebenläufigen Programmierung in Go wird das Konzept der Kanäle (channels) genutzt, welches eine relativ abstrahierte Möglichkeit der synchronen oder asynchronen Kommunikation zwischen Go-Routinen bietet. Ein Kanal ist dabei ein Speicherbereich, der durch Semaphore abgesichert ist und eine Warteschlange (buffered/asynchronous channel) oder lediglich eine Schnittstelle (unbuffered/synchronous channel) zur Verfügung stellt[10]. Über einen Kanal lassen sich dabei nur Daten eines festen Typs übertragen. Hierbei ist jedoch keinerlei Begrenzung hinsichtlich des Typs gegeben, auch Channels für Channels sind denkbar[11].

Ein Kanal wird durch den Aufruf make(chan typ) (synchron) bzw. make(chan typ, größe) (asynchron, wenn größe > 0) erstellt. Anschließend können Go-Routinen in den Channel schreiben, von ihm lesen und ihn schließen.

Bei synchronen Kanälen blockiert ein Lesezugriff, bis eine andere Go-Routine in den Channel schreibt bzw. der Schreibzugriff bis eine andere Routine liest. Bei asynchronen Kanälen tritt ein solches Verhalten nur auf, wenn der zu lesende Channel leer bzw. der zu schreibende Channel voll ist. Es gibt in Go keine Beschränkung hinsichtlich der Anzahl an Go-Routinen, die einen Channel lesen und schreiben. Trotz der ausgefeilten Synchronisationsmechanismen kann bei der Benutzung von Channels ein Deadlock auftreten, welcher die Go-Laufzeitumgebung veranlasst, das Programm zu beenden. Eine Go-Routine kann über das select Konstrukt auf mehreren Channels gleichzeitig lauschen, bzw. versuchen, in mehrere Channels zu schreiben, wobei das case-Statement ausgeführt wird, welches zuerst nicht mehr blockiert.

Daten werden mit kanal <- Wert in einen Kanal geschrieben und mit variable = <-kanal gelesen, wobei beim Lesen die Variablenzuweisung wegfallen kann. Das Lauschen auf einem Channel kann auch mit dem for-Konstrukt automatisiert werden, wobei die Schleife verlassen wird, sobald der Channel geschlossen wird.

Beispiel:

package main
 
import "fmt"
 
func zehnMal(kanal chan string) {
	// Argument empfangen
	sag := <-kanal
 
	// Zehn mal zurückschreiben
	for i := 0; i < 10; i++ {
		kanal <- sag
	}
 
	// Kanal schließen
	close(kanal)
}
 
func main() {
	// synchronen Kanal öffnen
	kanal := make(chan string) // oder make(chan string, 0)
 
	// Starten der parallelen Go-Routine „zehnMal()“
	go zehnMal(kanal)
 
	// Senden eines Strings
	kanal <- "Hallo"
 
	// Empfangen der Strings, bis der Channel geschlossen wird
	for s := range kanal {
		fmt.Println(s)
	}
 
	fmt.Println("Fertig!")
}

Im Beispiel ruft „main()“ die Go-Routine „zehnMal()“ auf, die einen empfangenen String zehn mal über den gleichen Kanal zurückgibt und ihn danach schließt. Durch den synchronen Kanal warten die beiden Go-Routinen aufeinander, sodass main() erst in die for-Schleife eintritt, wenn zehnMal() den String empfangen hat. Wäre der Kanal nicht synchron, könnte ein Deadlock auftreten, wenn main() die geschriebene Variable sofort wieder liest (und aus dem Puffer entfernt) und zehnMal() vergeblich auf sein Argument wartet. Wichtig ist auch, dass zehnMal() nach dem Schreiben der Strings den Kanal schließt, da main() sonst die Schleife nicht verlassen kann.

Implementierungen[Bearbeiten]

Es gibt mindestens zwei Compiler für Go, die auf Linux, Mac OS X, Windows und FreeBSD betrieben werden können und die Go 1 Spezifikation vollständig implementieren:

Gc
ist der offizielle Go-Compiler (je nach Architektur: 8g = x86, 6g = x86_64, 5g = ARM[12]) und wurde initial von Ken Thompson in C geschrieben, basiert auf der Plan 9 Toolchain und nutzt Yacc/Bison zum Parsen.
Gccgo
von Ian Taylor ist ein Go-Frontend für die GNU Compiler Collection (GCC). Es hat eine C++-Eingabe mit einem rekursiven Abstieg in Verbindung mit einer Standard-GCC-Ausgabe[13] und benötigt mehr Kompilierzeit verglichen zu Gc, produziert aber effizienteren Code. Die GNU Compiler Collection (GCC) unterstützt Go 1 mit Version 4.7.1 vollständig[14], der GNU Debugger (gdb) unterstützt Go seit Version 7.5.[15]

Beide Compiler implementieren eine parallele Mark-and-Sweep-Speicherbereinigung.

Der offizielle Compiler wird von dem Kommandozeilen-Werkzeug go begleitet, das als Fassade für verschiedene Werkzeuge dient, wie z. B. dem Installieren von Paketen aus Quelltext-Repositories im Internet wie etwa GitHub oder Google Code (go get), dem automatischen Formatieren von Quelltext (go fmt), dem Ausführen von Tests (go test), dem Erzeugen von Dokumentation aus Quelltext-Kommentaren (go doc) oder dem Kompilieren des Projektes (go build), so dass keinerlei Makefiles nötig sind, wenn eine empfohlene Verzeichnisstruktur eingehalten wird.

Geschichte[Bearbeiten]

Die Entwurfsphase begann am 21. September 2007, anfangs als 20-Prozent-Projekt auf Eigeninitiative von Robert Griesemer, Rob Pike und Ken Thompson. Bald darauf stießen weitere Entwickler dazu, und Go wurde zum Vollzeit-Projekt.[16] Am 30. Oktober 2009 wurde Go von Rob Pike in einem Google TechTalk präsentiert und die Veröffentlichung als freie Software angekündigt, die dann wie angekündigt am 10. November erfolgte.[17][18] Seitdem sind zahlreiche Beiträge von Entwicklern aus der Go-Community außerhalb Googles hinzugekommen. Am 28. März 2012 wurde Version 1 freigegeben.[19] Seitdem gelten Sprachspezifikation und Standardbibliothek als stabil und sollen innerhalb der 1.x-Serie keinen auf Quelltext-Ebene abwärts-inkompatiblen Änderungen mehr unterworfen werden.[20] Am 14. Mai 2013 wurde Go 1.1 freigegeben, das vor allem Performance-Verbesserungen an der Implementierung enthält.[21] Jeweils sechs Monate später erschienen Go 1.2 und Go 1.3.

Vom 24. bis zum 26. April 2014 fand die erste Konferenz zu Go, die GopherCon[22], in Denver statt.

Maskottchen[Bearbeiten]

Das Go-Maskottchen ist ein Gopher (engl. für Taschenratte) und wurde von Renée French entworfen, die auch Glenda, das Plan-9-Häschen entworfen hat. Das Logo und das Maskottchen stehen unter der Creative Commons Attribution 3.0 Lizenz.

Literatur[Bearbeiten]

Weblinks[Bearbeiten]

Quellen[Bearbeiten]

  1. Google-go-language
  2. Origins of Go's Concurrency Model
  3. Why Learn Go? – Kurzinterview mit Rob Pike (Video, englisch)
  4. http://talks.golang.org/2012/splash.article
  5. http://golang.org/doc/faq#no_pointer_arithmetic
  6. Golem.de-Artikel Go - schnelle Programmiersprache von Google
  7. http://golang.org/doc/faq#generics
  8. http://golang.org/doc/faq#unicode_identifiers
  9. http://blog.golang.org/2010/07/gos-declaration-syntax.html
  10. http://golang.org/doc/effective_go.html#channels
  11. http://golang.org/doc/effective_go.html#chan_of_chan
  12. Walter, Jörg: "Weniger ist mehr", erschienen in: c't 18/2011, S. 182ff
  13. golang.org/doc/faq#Implementation
  14. GCC 4.7 Release Series Changes, New Features, and Fixes
  15. GDB 7.5 Release Notes
  16. Informationen zur Geschichte in offizieller FAQ
  17. ursprüngliche Nachricht über die Veröffentlichung im Google Open Source Blog
  18. iX-Artikel vom 11. November 2009
  19. Freigabe der Version 1 im Go Programming Language Blog
  20. [1]
  21. [2]
  22. GopherCon