Das ewige Problem: „0“ links oder „Rechtsverschiebung“?
\n\nHaben Sie sich jemals gefragt, warum Bestellnummern in SQL-Abfragen wie 00042 und in Logs wie 23:05:07 aussehen? Ganz einfach: Mit Nullen aufgefüllte Zahlen werden auf eine Breite ausgerichtet und brechen die Sortierung nicht. Aber in Go gibt es im Gegensatz zu Python oder JavaScript keine eingebaute zfill-Methode. Und hier wird es interessant.
Auf Stack Overflow hat die Frage „How to pad a number with zeros when printing?“ Tausende von Aufrufen und Dutzende von Antworten erhalten. Die Leute suchen nicht nur nach einer Lösung, sondern nach einer schnellen Lösung. In diesem Artikel analysieren wir alle Möglichkeiten, Zahlen in Go mit Nullen aufzufüllen, vergleichen ihre Leistung und wählen die beste für Ihr Projekt aus.
\n\nWarum ist das für Go-Entwickler wichtig?
\n\nGo ist eine Sprache für die Systemprogrammierung, bei der jede Nanosekunde zählt. Wenn Sie einen hochbelasteten Dienst schreiben, kann eine falsche Zeichenfolgenformatierung zum Engpass werden. Besonders wenn Sie Tausende von Zahlen pro Sekunde formatieren.
\n\n- \n
- Protokollierung: Zeitstempel, Anfrage-IDs, Fehlercodes. \n
- Berichtserstellung: CSV, JSON, Tabellen. \n
- Netzwerkprotokolle: Feste Feldlängen. \n
- Spiele und Grafik: Textausrichtung in der Konsole. \n
Das Ignorieren der Leistung kann dazu führen, dass Ihr Dienst 10 % seiner Zeit mit der Zahlenformatierung verbringt. Glauben Sie nicht? Lassen Sie es uns überprüfen.
\n\nMethode Nr. 1: Klassiker mit fmt.Sprintf
\n\nDer offensichtlichste und am häufigsten empfohlene Weg ist die Verwendung von fmt.Sprintf mit dem Formatspezifizierer %0Xd, wobei X die Gesamtbreite der Zahl einschließlich der Nullen ist.
package main\n\nimport "fmt"\n\nfunc main() {\n num := 42\n padded := fmt.Sprintf("%05d", num)\n fmt.Println(padded) // Ausgabe: 00042\n}\n\n\nHier bedeutet %05d: „Gib die Zahl als dezimale Ganzzahl aus, fülle links mit Nullen auf eine Breite von 5 Zeichen auf“. Wenn die Zahl bereits länger ist (z. B. 123456), werden keine Nullen hinzugefügt – die Breite wird ignoriert.
Vorteile:
\n- \n
- Einfach und lesbar. \n
- Unterstützt negative Zahlen (das Vorzeichen steht links von den Nullen). \n
- Funktioniert mit verschiedenen Typen:
%05dfür int,%05.2ffür float. \n
Nachteile:
\n- \n
- Verwendet Reflexion innerhalb von
fmt– langsam. \n - Erzeugt einen zusätzlichen String und interface{}. \n
- Nicht geeignet für heiße Codepfade. \n
Methode Nr. 2: Schnelles strconv.FormatInt mit manuellem Auffüllen
\n\nWenn die Leistung kritisch ist, verwenden Sie das Paket strconv. Es arbeitet direkt mit Bytes, ohne Reflexion.
package main\n\nimport (\n "fmt"\n "strconv"\n "strings"\n)\n\nfunc padNumber(num int64, width int) string {\n s := strconv.FormatInt(num, 10)\n if len(s) >= width {\n return s\n }\n return strings.Repeat("0", width-len(s)) + s\n}\n\nfunc main() {\n fmt.Println(padNumber(42, 5)) // 00042\n}\n\n\nVorteile:
\n- \n
- 2-3 mal schneller als
fmt.Sprintf. \n - Keine Reflexion. \n
- Volle Kontrolle über die Logik. \n
Nachteile:
\n- \n
- Mehr Code. \n
- Negative Zahlen müssen separat behandelt werden (Vorzeichen links von den Nullen). \n
strings.Repeaterzeugt einen neuen String – kann weiter optimiert werden. \n
Methode Nr. 3: Maximale Leistung mit strings.Builder
\n\nFür diejenigen, die das Letzte herausholen wollen, gibt es eine Möglichkeit ohne unnötige Allokationen – die Verwendung von strings.Builder und die vorherige Pufferzuweisung.
package main\n\nimport (\n "fmt"\n "strconv"\n "strings"\n)\n\nfunc padNumberFast(num int64, width int) string {\n s := strconv.FormatInt(num, 10)\n if len(s)