Module string/string_builder
Mutable UTF-8 string builder for efficient incremental construction.
StringBuilder is the accumulator to reach for when a String is assembled
from many parts in a loop: appending is amortised O(1) into one growing
ArrayList(u8), and to_string() hands that buffer over instead of copying
it, so building an N-byte string costs O(N) once rather than twice. Repeated
a + b on String is what it replaces — that allocates a new string per
concatenation.
It also carries the three number/field renderers that used to live on
std/fmt's Writer (write_hex, write_f64, write_padded), which
retired into this type in v0.2.28 (#511). They sit in std/string only
because std/fmt already depends on std/string and the other direction
would be a cycle; std/fmt re-exports StringBuilder and Alignment so a
caller formatting text need not know that.
Lengths here are BYTES — len() is the buffer's byte count, the same basis
as String.len() (see docs/en-US/STRINGS.md). The one exception is
write_padded, whose width is a RUNE count so that it agrees with
FormatSpec.
Stability
unstable — the core (new, write_str, write_string, write_byte,
write_rune, len, to_string) is settled and heavily used, but the
helpers transplanted from Writer are not. write_hex and write_f64
render through a fixed-size stack buffer and TRUNCATE silently rather than
growing it (write_f64(f64(1.0e300), i32(2)) yields 63 digits of a
302-digit number — issues/stddoc-str-string-builder-write-f64-truncates.md),
and clear releases the buffer where Rust's String::clear keeps the
capacity (issues/stddoc-str-string-builder-clear-drops-capacity.md).
Freezing follows fixing those two and deciding whether number formatting
belongs on a text builder at all — it is here because of a dependency
direction, not because it was designed here.
Types
Where the text sits inside a padded field — the argument to
write_padded, and the same three cases FormatSpec parses from
< / > / ^.
It lives here rather than in std/fmt because write_padded does, and
std/fmt already depends on std/string; the other direction would be a
cycle. std/fmt re-exports it, so importing it from std/fmt works too.
Variants
| Variant | Fields | Description |
|---|---|---|
Left | ||
Right | ||
Center |
Mutable buffer for building a String incrementally.
Use StringBuilder when you need to construct a string from many parts,
appending bytes or strings in a loop, before converting to an immutable
String with to_string().
Example
sb := StringBuilder.new();
sb.write_str("Hello");
sb.write_str(", ");
sb.write_string(`world`);
sb.write_byte(u8(33)); // '!'
result := sb.to_string();
assert(result == `Hello, world!`, "built string");
Fields
| Name | Type | Description |
|---|---|---|
_buf | ArrayList(u8) |
Trait Implementations
impl(StringBuilder, ...)
new : (StringBuilder) fn() -> StringBuilderCreate a new, empty StringBuilder.
Returns: StringBuilder
with_capacity : (StringBuilder) fn(capacity : usize) -> StringBuilderCreate a StringBuilder pre-allocated for capacity bytes.
Parameters
| Name | Type | Notes |
|---|---|---|
capacity | usize |
Returns: StringBuilder
len : (StringBuilder) fn(self : StringBuilder) -> usizeReturns the current number of bytes in the buffer.
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder |
Returns: usize
is_empty : (StringBuilder) fn(self : StringBuilder) -> boolwrite_str : (StringBuilder) fn(self : StringBuilder, s : str) -> unitAppend a str (raw byte slice) to the buffer.
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
s | str |
Returns: unit
write_string : (StringBuilder) fn(self : StringBuilder, s : String) -> unitwrite_byte : (StringBuilder) fn(self : StringBuilder, b : u8) -> unitwrite_rune : (StringBuilder) fn(self : StringBuilder, r : rune) -> unitAppend a single Unicode code point, encoded as UTF-8.
Example
sb := StringBuilder.new();
sb.write_rune(rune(0x1F600)); // 😀
sb.write_rune(rune(0x41)); // 'A'
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
r | rune |
Returns: unit
write_line : (StringBuilder) fn(self : StringBuilder, s : String) -> unitAppend a String followed by a newline byte (\n).
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
s | String |
Returns: unit
to_string : (StringBuilder) fn(self : StringBuilder) -> StringDetach the accumulated bytes as a String, leaving the builder EMPTY and
still usable.
It does not copy and it does not consume the builder: the receiver is a
reference, and it starts over with a fresh buffer, so building an N-byte
string costs O(N) once. The returned String is therefore independent —
a later write_* on the same builder cannot mutate a string already
handed to a caller.
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder |
Returns: String
write_hex : (StringBuilder) fn(self : StringBuilder, n : u64) -> unitAppend an unsigned 64-bit integer in lowercase hexadecimal.
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
n | u64 |
Returns: unit
write_f64 : (StringBuilder) fn(self : StringBuilder, n : f64, precision : i32) -> unitAppend n with exactly precision decimal places.
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
n | f64 | |
precision | i32 |
Returns: unit
write_padded : (StringBuilder) fn(self : StringBuilder, s : str, width : usize, pad : rune, align : Alignment) -> unitAppend s padded to width RUNES with pad, aligned per align.
A s already at or over the width is written unpadded.
Width is a RUNE count, matching FormatSpec's {:width$} and Rust's.
It used to be a BYTE count here, so write_padded("héllo", 8, ' ', .Left)
emitted two spaces instead of three and the column did not line up — the
two width bases in one module disagreed
(issues/fixed/write-padded-counted-bytes-where-formatspec-counts-runes.md).
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder | |
s | str | |
width | usize | |
pad | rune | |
align | Alignment |
Returns: unit
clear : (StringBuilder) fn(self : StringBuilder) -> unitEmpty the builder.
This RELEASES the buffer rather than retaining its capacity — unlike
Rust's String::clear and unlike ArrayList.clear, both of which keep the
allocation for reuse. A builder cleared in a loop therefore reallocates
from zero on every pass; when that matters, keep a fresh builder per
iteration instead (it costs the same) or hand the bytes off with
to_string(), which detaches for the same price.
(issues/stddoc-str-string-builder-clear-drops-capacity.md)
Parameters
| Name | Type | Notes |
|---|---|---|
self | StringBuilder |
Returns: unit
impl(StringBuilder, Default(...))
default : (StringBuilder) fn() -> StringBuilderThe default value of the type.
Returns: StringBuilder