The bytes package works directly on []byte, covering most of what strings does for byte slices instead of strings, plus a growable Buffer type for building output without repeated allocations.
A byte is an alias for uint8, so a []byte is a slice of raw 8-bit values. Converting a string to []byte counts bytes, not characters, and a multi-byte UTF-8 rune like é takes two of them.
s := "héllo"
b := []byte(s)
fmt.Println(len(s), len(b), len([]rune(s)))The conversion copies the data, so writing to b never touches the original string s. Strings stay immutable no matter what happens to a byte slice built from one.
$ go run main.go
6 6 5
Héllo
hélloTry it
Examples
Contains and Index work on []byte the same way their strings counterparts work on string.
b := []byte("gopher")
fmt.Println(bytes.Contains(b, []byte("phe")))
fmt.Println(bytes.Index(b, []byte("her")))
fmt.Println(bytes.Equal(b, []byte("gopher")))true
3
trueTrimSpace only strips the ends. Replace's count argument caps how many matches get swapped; -1 means all of them.
s := []byte(" Gopher ")
fmt.Println(string(bytes.TrimSpace(s)))
r := bytes.Replace([]byte("oink oink oink"), []byte("oink"), []byte("moo"), 2)
fmt.Println(string(r))Gopher
moo moo oinkSplit cuts on every separator, dropping it from the result. Join puts a separator back between the pieces.
parts := bytes.Split([]byte("go,rust,python"), []byte(","))
for _, p := range parts {
fmt.Print(string(p), " ")
}
fmt.Println()
fmt.Println(string(bytes.Join(parts, []byte("|"))))go rust python
go|rust|pythonA zero-value Buffer is ready to write to immediately, no constructor call needed.
var buf bytes.Buffer
buf.WriteString("go")
buf.WriteByte(' ')
buf.WriteString("gopher")
fmt.Println(buf.String())
fmt.Println(buf.Len())go gopher
9Search and comparison
| Function | Description |
|---|---|
Equal(a, b []byte) bool | Reports whether a and b have the same length and content. |
Compare(a, b []byte) int | Returns -1, 0, or 1, ordering a before, equal to, or after b lexically. |
Contains(b, subslice []byte) bool bytes.Contains([]byte("seafood"), []byte("foo")) // true | Reports whether subslice appears anywhere within b. |
ContainsAny(b []byte, chars string) bool | Reports whether any UTF-8 code point in chars appears in b. |
ContainsRune(b []byte, r rune) bool | Reports whether the rune r appears in b. |
Index(b, subslice []byte) int bytes.Index([]byte("chicken"), []byte("ken")) // 4 | Returns the index of the first instance of subslice in b, or -1 if absent. |
IndexByte(b []byte, c byte) int | Returns the index of the first instance of byte c in b, or -1 if absent. |
IndexRune(b []byte, r rune) int | Returns the index of the first instance of rune r in b, or -1 if absent. |
LastIndex(b, subslice []byte) int | Returns the index of the last instance of subslice in b, or -1 if absent. |
Count(b, subslice []byte) int | Returns the number of non-overlapping instances of subslice in b. |
HasPrefix(b, prefix []byte) bool | Reports whether b starts with prefix. |
HasSuffix(b, suffix []byte) bool | Reports whether b ends with suffix. |
Transforming and splitting
| Function | Description |
|---|---|
ToUpper(b []byte) []byte | Returns a copy of b with every letter mapped to upper case. |
ToLower(b []byte) []byte | Returns a copy of b with every letter mapped to lower case. |
TrimSpace(b []byte) []byte | Returns a subslice of b with leading and trailing whitespace removed. |
Trim(b []byte, cutset string) []byte | Returns a subslice of b with leading and trailing characters in cutset removed. |
TrimLeft(b []byte, cutset string) []byte | Like Trim, but only removes from the left side. |
TrimRight(b []byte, cutset string) []byte | Like Trim, but only removes from the right side. |
TrimPrefix(b, prefix []byte) []byte | Removes prefix from b if present, otherwise returns b unchanged. |
TrimSuffix(b, suffix []byte) []byte | Removes suffix from b if present, otherwise returns b unchanged. |
Replace(s, old, new []byte, n int) []byte bytes.Replace([]byte("oink oink"), []byte("oink"), []byte("moo"), 1) // "moo oink" | Replaces the first n instances of old with new; n = -1 replaces all. |
ReplaceAll(s, old, new []byte) []byte | Like Replace with n = -1: every instance of old is replaced. |
Split(s, sep []byte) [][]byte | Splits s into subslices around every instance of sep. |
SplitN(s, sep []byte, n int) [][]byte | Like Split, but stops after n subslices; n = -1 behaves like Split. |
Fields(s []byte) [][]byte | Splits s around runs of whitespace, discarding empty results. |
Join(s [][]byte, sep []byte) []byte bytes.Join([][]byte{[]byte("go"), []byte("dev")}, []byte(".")) // "go.dev" | Concatenates the elements of s, placing sep between each one. |
Repeat(b []byte, count int) []byte | Returns a new slice of b repeated count times. |
Map(mapping func(rune) rune, s []byte) []byte | Returns a copy of s with each rune passed through mapping; a mapping that returns a negative value drops the rune. |
bytes.Buffer
bytes.Buffer is a growable buffer for building output piece by piece instead of repeatedly concatenating strings. Its zero value is ready to write to, with no constructor required.
var buf bytes.Buffer
buf.WriteString("go")
buf.WriteByte(' ')
buf.WriteString("gopher")
fmt.Println(buf.String())Buffer implements both io.Writer and io.Reader, so it drops into any function that expects one, including fmt.Fprintf.
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s scored %d", "Ada", 97)
fmt.Println(buf.String())| Function | Description |
|---|---|
NewBufferString(s string) *Buffer | Creates a Buffer pre-loaded with s, ready to be read. |
(*Buffer) Write(p []byte) (n int, err error) | Appends p to the buffer, growing it as needed; err is always nil. |
(*Buffer) WriteString(s string) (n int, err error) | Like Write, but takes a string directly, skipping a []byte conversion. |
(*Buffer) WriteByte(c byte) error | Appends a single byte to the buffer. |
(*Buffer) WriteRune(r rune) (n int, err error) | Appends the UTF-8 encoding of r to the buffer. |
(*Buffer) String() string | Returns the unread portion of the buffer as a string, without consuming it. |
(*Buffer) Bytes() []byte | Returns a slice of the unread portion of the buffer; valid only until the next write. |
(*Buffer) Len() int | Returns the number of unread bytes in the buffer. |
(*Buffer) Reset() | Empties the buffer while keeping its underlying storage for reuse. |
(*Buffer) Read(p []byte) (n int, err error) | Reads up to len(p) bytes into p and consumes them; returns io.EOF once drained. |
Putting it together
A short pipeline: trim the whitespace around each comma-separated field, then rebuild the line with a Buffer instead of repeated string concatenation.
$ go run main.go
go|rust|python
14