strings.SplitN arbeitet wie strings.Split, begrenzt das Ergebnis aber auf maximal n Stücke. Wird das Limit erreicht, landet der komplette ungesplittete Rest — inklusive aller noch vorhandenen Trenner — im letzten Element des Slices. Der typische Anwendungsfall ist der 2-Teile-Split mit n=2, bei dem nur am ersten Vorkommen des Trenners aufgeteilt wird. Für genau diesen Fall existiert seit Go 1.18 die idiomatischere Variante strings.Cut, die zusätzlich ein found-Flag liefert. SplitN bleibt nützlich für Limits mit n > 2 oder wenn der Rückgabewert-Slice direkt weiterverarbeitet werden soll.

Die Signatur ergänzt Split um den int-Parameter n, der das Maximum der Ausgabeteile steuert. Die Rückgabe ist wie immer ein []string — abhängig von n allerdings mit speziellen Sonderfällen für 0 und negative Werte.

Go signature.go
func SplitN(s, sep string, n int) []string

Der n-Parameter ist die eigentliche Besonderheit gegenüber Split. Er folgt einer klaren Konvention, die du verinnerlichen solltest, weil dieselben Regeln auch bei SplitAfterN, SplitNFunc und verwandten Funktionen gelten.

nVerhalten
n < 0Alle Stücke — identisch zu Split(s, sep)
n == 0nil (leerer Slice, kein Split)
n == 1Genau ein Element: der unveränderte Gesamtstring
n >= 2Maximal n Stücke; das letzte enthält den ungesplitteten Rest

Die Regel für n >= 2 ist der Kern: Die Funktion teilt höchstens n-1 Mal — danach landet alles Übrige am Stück im letzten Slot.

Mit n=2 splittet SplitN nur am ersten Vorkommen des Trenners. Das ist genau das, was du bei Header-Zeilen, key=value-Paaren oder URL-Schemata willst, wenn der Wert selbst den Trenner enthalten darf. Im folgenden Beispiel enthält ein typischer Authorization-Header zwischen Scheme und Token ein Leerzeichen — aber das Token darf theoretisch weitere Leerzeichen enthalten, die nicht zerschnitten werden sollen.

Go n2_split.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	header := "Bearer abc123 def456"
	parts := strings.SplitN(header, " ", 2)
	fmt.Printf("%q\n", parts)
	fmt.Println("Scheme:", parts[0])
	fmt.Println("Token: ", parts[1])
}
Output
["Bearer" "abc123 def456"]
Scheme: Bearer
Token:  abc123 def456

Mit Split würdest du drei Stücke erhalten und das Token am Leerzeichen zerreißen — SplitN mit n=2 schützt davor. Beachte: Ist der Trenner gar nicht vorhanden, bekommst du einen Slice mit einem Element zurück, nämlich dem Originalstring.

Für den 2-Teile-Split gibt es seit Go 1.18 die Funktion strings.Cut, die das Pattern direkter und sicherer ausdrückt. Sie liefert before, after und ein found bool, sodass du Fälle ohne Trenner sauber erkennst, ohne len(parts) zu prüfen.

Go cut_vs_splitn.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "key=value=mehr"

	// Variante A: SplitN mit n=2
	parts := strings.SplitN(s, "=", 2)
	fmt.Printf("SplitN: %q (len=%d)\n", parts, len(parts))

	// Variante B: Cut — idiomatischer für n=2
	before, after, found := strings.Cut(s, "=")
	fmt.Printf("Cut:    before=%q after=%q found=%v\n", before, after, found)
}
Output
SplitN: ["key" "value=mehr"] (len=2)
Cut:    before="key" after="value=mehr" found=true

Cut ist seit Go 1.18 die bevorzugte API für reine Zwei-Teile-Splits. Greife zu SplitN, wenn du echte Limits jenseits von 2 brauchst oder bestehenden Code pflegst, der schon Slice-Logik aufgebaut hat.

n=0 ist ein bewusster Sonderfall, der in der Praxis selten direkt vorkommt, aber bei dynamisch berechneten Limits aufpassen lässt. Das Ergebnis ist nil — kein leerer Slice mit einem leeren String, sondern wirklich nil mit Länge 0.

Go n_zero.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	result := strings.SplitN("a,b,c", ",", 0)
	fmt.Printf("result=%v len=%d nil?=%v\n", result, len(result), result == nil)
}
Output
result=[] len=0 nil?=true

Wer n aus einer Variable bezieht (z. B. Benutzereingabe oder Konfiguration), sollte deshalb prüfen, ob n=0 semantisch wirklich gewünscht ist — oft will man stattdessen n=-1 für „kein Limit".

Im realen HTTP-Code begegnet dir der Authorization-Header täglich. Das Format <scheme> <credentials> darf laut RFC 7235 im Credentials-Teil weitere Leerzeichen enthalten — etwa bei Base64-codierten Basic-Auth-Daten oder bei ungewöhnlichen Tokens. Ein naiver Split würde solche Werte zerreißen.

Go auth_header.go
package main

import (
	"errors"
	"fmt"
	"strings"
)

func parseAuth(header string) (scheme, creds string, err error) {
	parts := strings.SplitN(header, " ", 2)
	if len(parts) != 2 {
		return "", "", errors.New("ungueltiger Authorization-Header")
	}
	return parts[0], parts[1], nil
}

func main() {
	headers := []string{
		"Bearer eyJhbGciOi.JIUzI1NiIs",
		"Basic dXNlcjpwYXNz",
		"Token mit-extra space-anteil",
	}
	for _, h := range headers {
		scheme, creds, err := parseAuth(h)
		if err != nil {
			fmt.Println("Fehler:", err)
			continue
		}
		fmt.Printf("Scheme=%-7s Creds=%q\n", scheme, creds)
	}
}
Output
Scheme=Bearer  Creds="eyJhbGciOi.JIUzI1NiIs"
Scheme=Basic   Creds="dXNlcjpwYXNz"
Scheme=Token   Creds="mit-extra space-anteil"

Die Funktion bleibt damit robust gegen ungewöhnliche, aber zulässige Tokens. In modernem Go würdest du hier strings.Cut einsetzen, weil der found-Bool die len(parts) != 2-Prüfung lesbarer ersetzt.

Ein zweites typisches Pattern: das Parsen von key=value-Paaren, bei denen der Wert wiederum =-Zeichen enthalten darf — etwa Base64-Padding oder mathematische Ausdrücke. Erst Split auf & für die einzelnen Paare, dann SplitN(token, "=", 2) für jedes Paar, damit der Wert nicht weiter zerschnitten wird.

Go query_parse.go
package main

import (
	"fmt"
	"strings"
)

func parseQuery(q string) map[string]string {
	out := make(map[string]string)
	for _, token := range strings.Split(q, "&") {
		if token == "" {
			continue
		}
		kv := strings.SplitN(token, "=", 2)
		if len(kv) == 1 {
			out[kv[0]] = ""
			continue
		}
		out[kv[0]] = kv[1]
	}
	return out
}

func main() {
	q := "key1=value1&key2=val=eq&flag&data=YWJjPQ=="
	for k, v := range parseQuery(q) {
		fmt.Printf("%-5s -> %q\n", k, v)
	}
}
Output
key1  -> "value1"
key2  -> "val=eq"
flag  -> ""
data  -> "YWJjPQ=="

Für produktives Query-Parsing solltest du natürlich net/url.ParseQuery einsetzen — das übernimmt URL-Decoding und Fehlerbehandlung. Das Beispiel illustriert aber das Prinzip, bei dem SplitN mit n=2 den Wert intakt hält, selbst wenn er das Trennzeichen enthält.

n als Maximalzahl

n ist eine Obergrenze: die Funktion produziert höchstens n Stücke, nicht zwangsläufig genau n.

n < 0 wie Split

Negative Werte signalisieren „kein Limit" — das Verhalten ist identisch zu strings.Split(s, sep).

n == 0 ergibt nil

Bei n=0 kommt kein leerer String-Slice zurück, sondern nil mit len == 0.

n == 1 = ganzer String

n=1 liefert genau ein Element: den unveränderten Originalstring, unabhängig vom Trenner.

n=2 ist der Klassiker

Der häufigste Einsatz ist n=2 für Zwei-Teile-Splits an Header-, URL- oder Key-Value-Trennern.

Cut idiomatischer seit Go 1.18

Für reine 2-Teile-Splits ist strings.Cut mit seinem found-Bool die modernere und lesbarere Wahl.

Letztes Stück enthält Rest

Wird das Limit erreicht, landet der komplette ungesplittete Rest — inklusive aller weiteren Trenner — im letzten Slice-Element.

Threadsafe

Die Funktion arbeitet rein auf Eingabewerten und gibt einen frischen Slice zurück — sicher für parallelen Einsatz.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Das strings-Paket — String-Manipulation

Zur Übersicht