Warum ein Unterstrich vor import in Go? Wir analysieren anhand von Beispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Was verbirgt sich hinter dem Unterstrich bei import? Ein Leitfaden für alle, die Go tiefer verstehen wollen



Haben Sie jemals fremden Go-Code geöffnet und eine Zeile wie import _ "github.com/lib/pq" gesehen? Die erste Reaktion – „Ist das überhaupt legal? Meckert der Compiler nicht?“. Spoiler: Er meckert nicht. Mehr noch, es ist eines der elegantesten Features der Sprache, das bei Anfängern oft Fragen aufwirft. Lassen Sie uns klären, was dieses geheimnisvolle Unterstrich-Symbol vor dem Import in Go tatsächlich bewirkt und wie man es klug einsetzt.



Auf Stack Overflow hat diese Frage tausende Aufrufe – und das ist kein Wunder. Die Syntax sieht aus wie ein Tippfehler, aber dahinter steckt das tiefgreifende Konzept der Paketinitialisierung und Nebeneffekte. In diesem Artikel geben wir nicht nur eine trockene Definition, sondern zeigen reale Szenarien, in denen man auf _ nicht verzichten kann. Los geht's!



Problem: „Importiert, aber nicht verwendet“



In Go gibt es eine strenge Regel: Jedes importierte Paket muss verwendet werden. Sonst wird der Code nicht kompiliert. Dies dient der Sauberkeit und Leistung – keine tote Last. Aber was tun, wenn wir einfach den Code eines Pakets beim Programmstart ausführen müssen, ohne seine Funktionen direkt aufzurufen? Hier kommt der blank identifier (leerer Bezeichner) ins Spiel – das Symbol _.



Wenn Sie schreiben:

import _ "some/package"

– sagen Sie dem Compiler: „Ich weiß, dass ich keine Funktionen aus diesem Paket aufrufen werde, aber bitte führe seine init()-Funktion aus.“ Go führt die Initialisierung durch, gibt aber keinen Fehler „unused import“ aus.



Wie funktioniert init() und warum ist das wichtig?



Jedes Paket in Go kann eine oder mehrere init()-Funktionen enthalten. Sie werden automatisch beim Import des Pakets ausgeführt, vor der main()-Funktion. Die Ausführungsreihenfolge ist streng festgelegt:

  • Zuerst werden die Paketvariablen initialisiert
  • Dann wird init() aufgerufen
  • Wenn das Paket andere Pakete importiert, werden diese zuerst initialisiert


Ein Beispiel zur Veranschaulichung. Erstellen wir ein Paket config:

// config/config.gopackage config

var AppName string

func init() { AppName = "MyApp v1.0" println("Config initialized:", AppName)}


Jetzt können wir dieses Paket in main.go „still“ importieren:

// main.gopackage main

import ( _ "example.com/project/config" "fmt")

func main() { fmt.Println("Main function started")}


Ergebnis der Ausführung:

Config initialized: MyApp v1.0Main function started


Beachten Sie: Wir haben config.AppName nicht aufgerufen – wir haben das Paket einfach mit Unterstrich importiert, und seine init()-Funktion wurde automatisch ausgeführt. Dies ist die grundlegende Mechanik, auf der viele reale Lösungen aufbauen.



Hauptszenario: Registrierung von Datenbanktreibern



Das häufigste Beispiel für die Verwendung von import _ im Production-Code ist die Registrierung von Datenbanktreibern. Das Standardpaket database/sql verwendet das „Factory“-Muster: Alle Treiber registrieren sich über sql.Register() in ihren eigenen init()-Funktionen.



Sehen Sie, wie PostgreSQL (Treiber lib/pq) eingebunden wird:

import (    "database/sql"    _ "github.com/lib/pq" // registriert den Treiber "postgres")

func main() { db, err := sql.Open("postgres", "user=... dbname=...") // ...}


Im Inneren von lib/pq steht in init() etwa Folgendes:

func init() {    sql.Register("postgres", &Driver{})}


Ohne den leeren Import wäre der Treiber nicht registriert, und sql.Open("postgres", ...) würde einen Fehler „unknown driver“ zurückgeben. Dasselbe gilt für MySQL, SQLite, Oracle und andere Datenbanken.

Blogs

Buchempfehlungen