Summary#
^n is the position n elements before the end, so xs[^1] is the last element — on a string, an array and a
list. a..b is the range from a up to (not including) b; either end may be left out, and either may be written
from the end: s[1..3], s[2..], arr[..2], s[^3..]. A string's range is a substring, an array's is a new array.
Signature#
xs[^<int n>] // the element n before the end — xs[xs.Length - n] (Count on a list)
s[<start>..<end>] // string → string, end exclusive; either bound may be ^n or omitted
arr[<start>..<end>] // T[] → a new T[]Description#
- The same answers as C#.
^1is the last element and^0is one past it (reading it faults, as in C#).s[a..b]iss.Substring(a, b - a)— an out-of-range bound faults the waySubstringdoes. - Where they are read. Inside an indexer. C# also lets
^1and1..3be stored asIndex/Rangevalues; Osy# has no such value, so outside[ ]they are refused by name with the indexer to write instead. - A list takes
^nbut not a range — as in C#,List<T>has no range indexer; copy a slice withxs.GetRange(start, count). - The value is read once per use. The indexed value and each bound must be something that can be read again — a variable, a field, a literal — because the lowering reads the length and then the element. Anything else (a call) is refused with the fix: bind it to a local first.
- Precedence is C#'s:
..binds tighter than arithmetic, so a computed bound is parenthesised —s[1..(n - 1)].
Examples#
string Last(string s) => $"{s[^1]}"; // "o" for "hello"
string Middle(string s) => s[1..^1]; // "ell"
int[] Head(int[] xs) => xs[..2]; // { 1, 2 } of { 1, 2, 3 }
int LastOf(List<int> xs) => xs[^1];See also#
- List indexer —
list[i], read and write - Array literals — building the arrays and lists a range slices