Strings
The String type is a UTF-8 encoded, immutable string. Instances of this type
are created using single or double quotes:
'hello'
"hello"
Strings support escape sequences and interpolation:
'hello\tworld' # => 'hello world'
'number: ${10}' # => 'number: 10'
Single and double quoted strings are the same, i.e. both support escape sequences and interpolation.
Ownership and copying
Strings are value types and use atomic reference counting to make copying and sharing them cheap:
let a = 'foo'
let b = a
Here we can use both a and b after b is defined, because b is given a
"copy" of the string, instead of taking over ownership.
StringBuffer
Because String is immutable, operations such as concatenations create new
String instances. This can be inefficient when performing operations that
produce many intermediate String instances. To work around this, the type
std.string.StringBuffer is used:
import std.string (StringBuffer)
class async Main {
fn async main {
let buf = StringBuffer.new
buf.push('hello ')
buf.push('world, ')
buf.push('how are you ')
buf.push('doing?')
buf.into_string # => 'hello world, how are you doing?'
}
}
Here we push a bunch of String values into the buffer, then concatenate them
together without producing intermediate String instances by calling
StringBuffer.into_string.
String slicing
The String type offers two ways of slicing up a String:
String.slice: slices aStringinto aByteArrayusing a byte rangeString.substring: slices aStringinto anotherStringusing an extended grapheme cluster (i.e. character) range
For example:
'😊'.slice(start: 0, size: 4) # => [240, 159, 152, 138]
'😊'.substring(start: 0, chars: 1) # => '😊'
Slicing a String using String.slice is a constant-time operation, while
String.substring runs in linear time due to the use of extended grapheme
clusters.
String iteration
The String type offers two ways of iterating over its contents:
String.bytes: returns an iterator over the bytes in theStringString.chars: returns an iterator over the extended grapheme clusters in theString