Strings
A string is a length and some bytes on the heap. The standard library gives you seventeen ways to work with them, and every one produces a new string, because in Sure, strings do not change — they are replaced.
Basics
+ concatenates (and allocates). == and
!= compare contents, not identity. len counts
bytes. Escapes cover the usual suspects: \n,
\t, \r, \", \\,
\0.
func main() -> Int {
let greeting = "hello" + ", " + "world"
print(greeting == "hello, world") // true
print(len(greeting)) // 12
return 0
}
Taking strings apart
find returns the index of a substring or -1.
slice cuts by byte range, start inclusive, end exclusive,
clamped to the string — slicing cannot fail, only disappoint.
split divides on a separator into a
[String].
func main() -> Int {
let request = "GET /index.html HTTP/1.1"
let first_space = find(request, " ")
let rest = slice(request, first_space + 1, len(request))
let path = slice(rest, 0, find(rest, " "))
print(path) // /index.html
let parts = split(request, " ")
print(parts[0]) // GET
print(len(parts)) // 3
return 0
}
That is real protocol parsing, and it is the exact code the web server
in chapter 10 uses. join is split's inverse:
join(parts, " ") reassembles.
Questions and transformations
| Call | Answers |
|---|---|
| contains(s, sub) | is sub in there? |
| starts_with(s, p), ends_with(s, p) | the edges |
| trim(s) | a copy without surrounding whitespace |
| upper(s), lower(s) | ASCII case, changed |
| replace(s, old, new) | every occurrence, replaced |
| byte_at(s, i) | one byte, as an Int (bounds-checked) |
| chr(n) | one byte, as a String |
func main() -> Int {
let shout = upper(trim(" make it loud "))
print(shout + "!") // MAKE IT LOUD!
print(replace("a-b-c", "-", "::")) // a::b::c
print(byte_at("A", 0)) // 65
print(chr(66)) // B
return 0
}
To numbers and back
str(x) renders an Int, Float,
or Bool. to_int(s) and
to_float(s) parse; a string that isn't a number parses to
zero, calmly. Validate first if zero would flatter your input.
func main() -> Int {
let port = to_int("8080")
print(port + 1) // 8081
print(to_float("2.5")) // 2.5
print(to_int("sure")) // 0
return 0
}
len, slice, and byte_at
count bytes; UTF-8 text passes through everything intact, but a slice
boundary in the middle of a multi-byte character is your slice boundary,
faithfully executed. The library does what you say, which is the most
and the least it can do.