strings.Repeat erzeugt einen neuen String, der den Eingabestring s insgesamt n-mal aneinandergehängt enthält. Die Funktion ist eines der einfachsten Werkzeuge im strings-Paket, hat aber zwei nicht-offensichtliche Eigenheiten: ein negatives n löst eine Panic aus, und auch ein zu großer Ergebnis-Output kann zur Panic führen, wenn len(s) * n die maximale Slice-Länge überschreiten würde.
In der Praxis taucht Repeat überall dort auf, wo Padding oder Trennlinien generiert werden: ASCII-Boxes, Test-Strings, Indentation, Initialisierung von Default-Werten. Performance-technisch ist die Funktion optimal — sie alloziert genau einmal den Ziel-Speicher und kopiert mit copy() in optimierten Doublings, statt naiv in einer Schleife zu konkatenieren.
Die Signatur ist minimal: Eingabestring und Wiederholungszahl, ein String zurück. Kein Fehlerrückgabewert, dafür Panics für die zwei pathologischen Fälle.
func Repeat(s string, count int) stringSowohl n = 0 als auch s = "" sind vollkommen gültig und liefern einen leeren String zurück. Nur ein negativer count ist verboten — die Implementierung prüft explizit darauf und ruft panic auf.
Im Normalfall verhält sich Repeat exakt wie erwartet: der Eingabestring wird n-mal aneinandergehängt. Das funktioniert mit beliebigen Strings, inklusive UTF-8-Multibyte-Sequenzen und leeren Strings.
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.Repeat("ab", 3))
fmt.Printf("%q\n", strings.Repeat("-", 10))
fmt.Printf("%q\n", strings.Repeat("äöü", 2))
fmt.Printf("%q\n", strings.Repeat("xyz", 0))
fmt.Printf("%q\n", strings.Repeat("", 100))
}"ababab"
"----------"
"äöüäöü"
""
""Wie zu sehen, bleiben Multi-Byte-Runen wie ä, ö, ü natürlich intakt — die Funktion arbeitet auf Byte-Ebene, aber die Konkatenation ganzer UTF-8-Sequenzen ist ohnehin byte-sicher. Sowohl count = 0 als auch ein leerer Eingabestring liefern den leeren String zurück, ohne dass etwas allokiert würde.
Ein negativer count ist die häufigste Panic-Falle. Die Implementierung könnte alternativ einen leeren String zurückgeben oder den Wert mit max(0, count) clampen — bewusst tut sie das nicht, weil ein negativer Repeat-Count fast immer auf einen Bug im Aufruferkontext hinweist.
package main
import (
"fmt"
"strings"
)
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}()
_ = strings.Repeat("x", -1)
fmt.Println("nicht erreicht")
}recovered: strings: negative Repeat countPraktische Konsequenz: stammt der count-Wert aus Nutzereingaben, Konfigurationsdateien oder Berechnungen, sollte er vor dem Aufruf auf >= 0 geprüft werden. Ein if n < 0 { n = 0 } direkt vor Repeat ist eine billige Versicherung gegen Crash-Bugs.
Die zweite, weniger bekannte Panic-Quelle ist ein Overflow der Ergebnislänge. Wenn len(s) * n die maximale Slice-Länge überschreiten würde (auf 64-Bit-Systemen praktisch nie, auf 32-Bit-Systemen oder bei sehr großen Strings durchaus erreichbar), gibt es ebenfalls eine Panic mit der Meldung "strings: Repeat output length overflow".
In Tests und Fuzzing kann das relevant werden, wenn s aus untrusted Eingaben stammt und mit einem großen n multipliziert wird. Eine schnelle Vorabprüfung mit n > 0 && len(s) > maxInt/n schützt davor — in normalen Produktionscode ist das aber selten nötig, weil die nötigen Größenordnungen außerhalb realistischer Anwendungsfälle liegen.
strings.Repeat ist intern darauf optimiert, genau einmal Speicher zu allozieren. Die Größe des Ziel-Strings ist im Voraus bekannt (len(s) * count), also wird ein passender Byte-Buffer angelegt und der Eingabestring per copy() hineingeschrieben.
Statt naiv count-mal zu kopieren, verdoppelt die Implementierung den bereits geschriebenen Bereich in jeder Iteration: erst s, dann ss, dann ssss, dann ssssssss — bis count-Kopien erreicht sind. Das reduziert die Anzahl der Kopier-Operationen von O(n) auf O(log n) mit jeweils größeren Block-Kopien, was auf modernen CPUs deutlich schneller ist.
package main
import (
"fmt"
"strings"
)
func naiveRepeat(s string, n int) string {
out := ""
for i := 0; i < n; i++ {
out += s // jedes += alloziert neuen String
}
return out
}
func main() {
a := strings.Repeat("ab", 5)
b := naiveRepeat("ab", 5)
fmt.Println(a == b, a)
}true abababababDie naive Variante alloziert n Mal, weil jeder +=-Aufruf einen neuen String erzeugt — bei großen n katastrophal. strings.Repeat ist deshalb nicht nur die idiomatische, sondern auch die einzig vertretbare Wahl, wenn count größer als zwei oder drei ist.
Der häufigste Anwendungsfall ist die Erzeugung von Padding oder Trennlinien für CLI-Ausgaben, Log-Header oder ASCII-Boxes. Mit strings.Repeat ist das eine einzelne Zeile statt einer Schleife.
package main
import (
"fmt"
"strings"
)
func headerLine(title string, width int) string {
pad := width - len(title) - 2
if pad < 0 {
pad = 0
}
left := pad / 2
right := pad - left
return strings.Repeat("=", left) + " " + title + " " + strings.Repeat("=", right)
}
func main() {
fmt.Println(headerLine("Konfiguration", 40))
fmt.Println(strings.Repeat("-", 40))
fmt.Println(headerLine("Ende", 40))
}============ Konfiguration ============
----------------------------------------
================ Ende =================Achtung: len(title) zählt Bytes, nicht Runen — bei UTF-8-Strings mit Umlauten wäre utf8.RuneCountInString(title) korrekter. Für reine ASCII-Header funktioniert die Byte-Variante einwandfrei.
In Tests und Benchmarks taucht Repeat häufig auf, wenn große Strings für Stress-Tests, Buffer-Tests oder Boundary-Tests benötigt werden. Statt eine 1-MB-Datei zu pflegen, generiert man den Teststring direkt im Code.
package main
import (
"fmt"
"strings"
)
func main() {
// 1 KiB an "a"-Zeichen
stress := strings.Repeat("a", 1024)
fmt.Println("Länge:", len(stress))
// Wiederholtes Pattern für Parser-Tests
csv := strings.Repeat("foo,bar,baz\n", 3)
fmt.Print(csv)
}Länge: 1024
foo,bar,baz
foo,bar,baz
foo,bar,bazVorteil dieser Vorgehensweise: die Testintention bleibt im Code sichtbar (1024 Zeichen), keine externe Datei muss synchron gehalten werden, und der Speicher wird nur dann reserviert, wenn der Test tatsächlich läuft. Für reproduzierbare Edge-Cases ist strings.Repeat deshalb das natürliche Werkzeug.
Negativer count panicked
strings.Repeat(s, -1) löst eine Panic aus — vor unsicheren Eingabewerten mit if n < 0 { n = 0 } absichern.
Overflow-Panic bei riesigem Ergebnis
Wenn len(s) * n die Slice-Grenze überschreitet, gibt es "output length overflow" — relevant nur bei extremen Größenordnungen.
Eine einzige Allokation
Die Implementierung alloziert genau einmal mit korrekter Endgröße und kopiert per Doubling — schnellster Weg zum Repeat.
Niemals += in der Schleife
Wiederholtes out += s alloziert n-mal und ist bei großen Counts dramatisch langsamer als Repeat.
count = 0 ist gültig
Liefert den leeren String ohne Allokation — nützlich für konditionalen Aufruf ohne separates if.
UTF-8-sicher
Da nur ganze Strings konkateniert werden, bleiben Multi-Byte-Sequenzen automatisch intakt.
Padding-Pattern Standard
Idiomatisch für ASCII-Boxes, CLI-Trennlinien, Log-Header — kompakter als Schleifen, schneller als +=.
Threadsafe
Keine geteilten Zustände, Strings sind immutable — parallele Aufrufe sind ohne Synchronisation möglich.
Weiterführende Ressourcen
Externe Quellen
strings.Repeatbytes.Repeat(byte-orientiertes Pendant)strings.Builder(für komplexere Build-Up-Szenarien)