strings.LastIndexByte liefert den Byte-Offset des letzten Vorkommens eines einzelnen Bytes c in einem String s — oder -1, wenn das Byte nirgendwo auftaucht. Im Unterschied zu LastIndex, das einen kompletten Substring sucht, beschränkt sich LastIndexByte auf genau ein Byte und arbeitet daher mit einer extrem schlanken Reverse-Scan-Schleife, die ohne Allokation auskommt.

Das ist die Standardwahl, wenn das gesuchte Trennzeichen ein ASCII-Zeichen ist und am Stringende vermutet wird: der Punkt vor der Dateiendung, der letzte Slash in einem Pfad, das letzte \n in einem Buffer oder das letzte Komma einer CSV-Zeile. Sobald aber Multi-Byte-Codepoints im Spiel sind — etwa Umlaute oder Emojis — verändert sich das Bild grundlegend, weshalb der Byte- vs. Rune-Unterschied weiter unten zentral ist.

Die Signatur ist identisch aufgebaut zu IndexByte, nur dass die Suchrichtung umgekehrt verläuft. Der Rückgabewert ist ein Byte-Offset im Bereich [0, len(s)-1] oder -1.

Go signatur.go
func LastIndexByte(s string, c byte) int

Wichtig: der Parameter c ist vom Typ byte (Alias für uint8), nicht rune. Damit ist die Funktion auf den Wertebereich 0..255 festgenagelt und kann konzeptionell nur Single-Byte-Werte finden — selbst wenn der Eingabestring viele Multi-Byte-Codepoints enthält.

Die Implementation läuft vom letzten Byte rückwärts durch den String und gibt den ersten gefundenen Treffer-Offset zurück. Sobald ein Match vorliegt, bricht die Schleife ab — bei Trennern, die typischerweise nahe am Stringende stehen, ist das deutlich schneller als ein LastIndex mit Substring-Suche.

Go reverse_scan.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "a.b.c.d.txt"
	fmt.Println(strings.LastIndexByte(s, '.'))
	fmt.Println(strings.LastIndexByte(s, 'a'))
	fmt.Println(strings.LastIndexByte(s, 'z'))
}
Output
7
0
-1

Der erste Aufruf landet beim Punkt vor txt an Position 7 — die drei vorgelagerten Punkte werden ignoriert. Der zweite Aufruf zeigt, dass auch ein einziges Vorkommen ganz am Anfang gefunden wird, weil der Reverse-Scan den gesamten String durchläuft, wenn nötig. Der dritte Aufruf demonstriert das -1-Sentinel.

Dieselbe Falle wie bei IndexByte: bei Multi-Byte-UTF-8 sucht LastIndexByte ein einzelnes Byte, nicht einen Codepoint. Ein deutscher Umlaut wie ä belegt in UTF-8 zwei Bytes (0xC3 0xA4), und ein Aufruf mit einem dieser einzelnen Bytes liefert zwar einen Offset, der aber keinem sinnvollen Zeichen entspricht.

Go byte_vs_rune.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "Straße — Maßstab"

	// 'ß' ist KEIN Byte, sondern zwei Bytes (0xC3 0x9F).
	// Die naive Suche trifft willkürlich auf das erste Byte:
	fmt.Println(strings.LastIndexByte(s, 0xC3))

	// Korrekt: per LastIndex mit String-Repräsentation der Rune.
	fmt.Println(strings.LastIndex(s, string('ß')))
}
Output
12
12

Der erste Wert ist nur deshalb sinnvoll, weil 0xC3 zufällig das Lead-Byte beider ß ist — in echten Suchen führt das schnell zu kaputten Offsets mitten in einem Codepoint. Für alles oberhalb von 0x7F ist LastIndex(s, string(r)) die saubere Variante, weil sie die vollständige UTF-8-Sequenz matched.

Auf einem leeren String gibt es nichts zu finden, und das Sentinel -1 ist die einzig konsistente Antwort. Der gesuchte Byte-Wert spielt keine Rolle.

Go leer.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	fmt.Println(strings.LastIndexByte("", '.'))
	fmt.Println(strings.LastIndexByte("", 0))
}
Output
-1
-1

Das deckt sich mit dem Verhalten aller Index*-Varianten in strings und macht die -1-Prüfung zum Standard-Idiom, bevor der Rückgabewert als Offset verwendet wird.

Die drei Funktionen lassen sich entlang zweier Achsen unterscheiden: Suchrichtung und Mustertyp. LastIndexByte ist die spezialisierte Kombination aus rückwärts und Single-Byte.

FunktionSuchtRichtungAllokationMulti-Byte-sicher
IndexByte(s, c)ein Bytevorwärtskeinenein (nur ASCII sinnvoll)
LastIndexByte(s, c)ein Byterückwärtskeinenein (nur ASCII sinnvoll)
LastIndex(s, substr)Substringrückwärtskeineja (matcht ganze Sequenzen)

Faustregel: ASCII-Trenner am Stringende — LastIndexByte. Multi-Byte-Codepoint oder mehrere Zeichen — LastIndex mit explizitem String.

Der klassische Anwendungsfall ist das Abspalten einer Dateiendung. Da der letzte Punkt typischerweise nur wenige Bytes vor dem Stringende steht, ist der Reverse-Scan praktisch in O(1) erledigt und allokationsfrei.

Go dateiendung.go
package main

import (
	"fmt"
	"strings"
)

func ext(name string) string {
	i := strings.LastIndexByte(name, '.')
	if i < 0 {
		return ""
	}
	return name[i:]
}

func main() {
	fmt.Printf("%q\n", ext("report.final.pdf"))
	fmt.Printf("%q\n", ext("archive.tar.gz"))
	fmt.Printf("%q\n", ext("Makefile"))
}
Output
".pdf"
".gz"
""

Für portable Pfade ist path/filepath.Ext allerdings die robustere Wahl, weil es Plattform-Trenner berücksichtigt und Edge-Cases wie führende Punkte sauber behandelt. LastIndexByte ist ideal, wenn man bewusst auf der Byte-Ebene operiert — etwa in einem Tokenizer oder Logfile-Parser, wo filepath semantisch fehl am Platz wäre.

Beim tail-artigen Lesen eines Buffers will man oft schnell den Anfang der letzten Zeile finden, ohne den gesamten Buffer in Zeilen aufzuteilen. Der Reverse-Scan nach \n löst das in einem einzigen Aufruf.

Go letzte_zeile.go
package main

import (
	"fmt"
	"strings"
)

func lastLine(buf string) string {
	// Trailing-Newline ignorieren, falls vorhanden.
	buf = strings.TrimRight(buf, "\n")
	i := strings.LastIndexByte(buf, '\n')
	if i < 0 {
		return buf
	}
	return buf[i+1:]
}

func main() {
	log := "2026-05-22 INFO  start\n2026-05-22 WARN  retry\n2026-05-22 ERROR fail\n"
	fmt.Printf("%q\n", lastLine(log))
}
Output
"2026-05-22 ERROR fail"

Der Trick mit TrimRight macht den Algorithmus tolerant gegenüber einem optionalen Trailing-Newline — typischer Sonderfall in Logdateien. Der eigentliche Suchaufruf bleibt ein einziger Reverse-Scan, der bei kurzen letzten Zeilen praktisch sofort terminiert.

Reverse-Scan

LastIndexByte läuft vom letzten Byte rückwärts und bricht beim ersten Treffer ab — die natürliche Implementierung für „letztes Vorkommen".

Schnell bei kurzem Tail

Wenn das gesuchte Byte typischerweise nahe am Stringende steht (Dateiendung, letzte Zeile), ist die Funktion praktisch konstant in der Laufzeit.

Nur ASCII-sicher

Sinnvoll einsetzbar ist die Funktion nur für Byte-Werte unter 0x80 — also klassisches ASCII inklusive Steuerzeichen.

Byte ≥ 128 vermeiden

Bei Codepoints oberhalb von ASCII liefert LastIndex(s, string(r)) korrekte UTF-8-Ergebnisse — LastIndexByte trifft dort nur Lead- oder Continuation-Bytes.

-1 bei Nicht-Treffer

Der Rückgabewert -1 ist das einheitliche Sentinel und sollte vor jeder Slice-Operation geprüft werden.

Threadsafe und allokationsfrei

Wie alle strings-Suchfunktionen ist LastIndexByte rein lesend, threadsicher und allokationsfrei — geeignet für Hot Paths.

Ideal für Dateiendungen und Tails

Dateiendungen, letzte Zeile aus einem Buffer, letzter Slash in einem Pfad — die typischen Stringende-Trenner sind genau das Spielfeld dieser Funktion.

filepath.Ext oft die bessere Wahl

Für plattformbewusste Pfad-Operationen ist path/filepath.Ext robuster — LastIndexByte glänzt dort, wo bewusst auf Byte-Ebene gearbeitet wird.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

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

Zur Übersicht