Collections
Collections
std::collections is auto-imported, so these names are used bare.
Array
[public] class Array<T> impl Index<number, T>, IndexRef<number, T> {
[public] fn size() => number
[public] fn push(value: T)
[public] fn is_empty() => bool
[public] fn first() => T?
[public] fn last() => T?
[mutates] fn pop() => T?
[mutates] fn set(i: number, value: T)
[mutates] fn insert(i: number, value: T)
[mutates] fn remove_at(i: number) => T
[mutates] fn clear()
[mutates] fn reverse()
[public] fn iter() => ArrayIterator<T>
}Functional operations, all taking closures:
[public] fn map<U>(transform: closure(T) => U) => Array<U>
[public] fn filter(predicate: closure(T) => bool) => Array<T>
[public] fn reduce<U>(initial: U, combine: closure(U, T) => U) => U
[public] fn find(predicate: closure(T) => bool) => T?
[public] fn any(predicate: closure(T) => bool) => bool
[public] fn all(predicate: closure(T) => bool) => bool
[public] fn for_each(action: closure(T) => void)
[public] fn zip<U>(other: Array<U>) => Array<Pair<T, U>>
[public] fn flat_map<U>(transform: closure(T) => Array<U>) => Array<U>
[public] fn take(amount: number) => Array<T>
[public] fn drop(amount: number) => Array<T>
[public] fn count_where(predicate: closure(T) => bool) => numberSorting and searching are pluggable. The default algorithms are merge sort and
linear search; set_sort_method and set_search_method change them, and
sort_using / search_using override for one call.
items.sort(closure(a: string, b: string) => number {
return a.size() - b.size()
})A comparison closure returns a negative number when the first argument sorts first, zero when they tie, positive otherwise. A search probe returns negative when the element is below the target and zero on a match.
Two hazards. Indexing is not bounds checked, so an out-of-range index
reads or writes past the buffer. And the search family returns -1 on no
match, while find, first, last, and pop return optionals.
Literal shorthand
Arrays and maps have a literal form, so a small collection does not need a
constructor and a run of push calls:
let names = #["alpha", "beta", "gamma"]
let ports = #{"http": 80, "https": 443}An array literal is #[ followed by comma-separated values. A map literal is
#{ followed by key: value pairs. Element and value types are inferred from
the contents, so an annotation is optional:
let names: Array<string> = #["alpha", "beta"]Both produce the ordinary Array and Map types, so everything on the rest of
this page applies to them.
Map
[public] class Map<KT: impl Hash, impl Equals, VT> {
[public] fn size() => number
[public] fn set(key: KT, value: VT)
[public] fn get(key: KT) => VT?
[public] fn contains(key: KT) => bool
[public] fn remove(key: KT)
[public] fn key_list() => Array<KT>
[public] fn value_list() => Array<VT>
[public] fn entries() => Array<Pair<KT, VT>>
[public] fn for_each(action: closure(KT, VT) => void)
}Open addressing with linear probing, growing past three-quarters full. Key order is unspecified.
Map has no iter(), so for k in map is a compile error. Iterate
map.key_list() or map.entries(), or use for_each.
IndexMap
Same surface as Map, but key_list, value_list, and entries return keys in
insertion order. remove is linear rather than constant time. JsonObject
is built on it, which is why parsed JSON round-trips with stable key order.
The rest
StringBuilder accumulates text and produces a string with build().
Pair<A, B> holds two values reached with get_first() and get_second(), and
is what destructuring binds against. List<T> is Array<T> under a name that
reads as a sequence. split(text, separator) returns an Array<string>;
consecutive separators produce empty pieces, and an empty separator returns the
whole text as one piece.