- Antril
- Referencia
- Patrones
Esta página aún no está traducida al español. Leer la versión en inglés
Patterns
The patterns of Antril - discards, var, constants, comparisons, ranges, and/or/not, types, positions, properties and null - and where they are used - is, switch statements and switch expressions, with when guards.
En esta página
A pattern tests a value and can take parts of it into new variables. Patterns are used in three places:
| Where | Form |
|---|---|
is |
value is pattern gives a bool. |
| A switch statement | switch (value) { pattern [when condition] => statement … } |
| A switch expression | value switch { pattern [when condition] => result, … } |
The patterns
| Pattern | Matches |
|---|---|
_ |
Anything. |
var name |
Anything, and names it. |
42, "stop", Color.Red, Limit |
A value equal to the constant. |
null |
A null value. |
< 0, <= 9, > 100, >= 90, != 3 |
A number that compares so with the constant. |
1..10, 1..=9 |
A number in the range: .. leaves out the end, ..= includes it. |
p and q |
A value both match. |
p or q |
A value either matches. |
not p |
A value p does not match. |
(p) |
Grouping. |
T, T name |
A value of type T (a class, an interface, a primitive, a generic type), optionally named. |
T(p, q, …), (p, q, …) |
The value's positions, matched one by one. |
T { A: p, B: q }, { A: p } |
The value's fields or properties, matched by name. |
not binds tighter than and, and and tighter than or: < 0 or > 10 and not 20 is < 0 or (> 10 and (not 20)). Use parentheses for anything else.
import System;
Grade(i32 score) : str => score switch
{
< 0 or > 100 => "invalid",
>= 90 => "A",
80..90 => "B",
70..=79 => "C",
not 0 => "D",
_ => "zero",
};
Main()
{
loop (i32 s in [95, 85, 75, 50, 0, 101])
Console.Write(Grade(s) + " ");
Console.WriteLine();
Console.WriteLine(5 is not (1 or 2));
Console.WriteLine(3 is != 3);
}
larva run
A B C D zero invalid
true
false
Constants
A constant pattern is a literal, a const, an enum member, or an expression made of them (it is read up to the shift operators, so 1 + 1 works and a comparison does not). It compares with == of the value's type: numbers, bool, strings by content, enum members.
import System;
public enum Color { Red, Green, Blue }
const i32 Limit = 10;
Main()
{
Color c = Color.Green;
switch (c)
{
Color.Red => Console.WriteLine("red");
Color.Green or Color.Blue => Console.WriteLine("green or blue");
}
Console.WriteLine("stop" switch { "go" => 1, "stop" => 2, _ => 0 });
Console.WriteLine(10 switch { Limit => "the limit", _ => "below" });
}
larva run
green or blue
2
the limit
A pattern constant of a type the value cannot have is AN2090.
Comparisons and ranges
<, <=, >, >= and != compare numbers (AN2086 for other types); the bound is a constant. A range a..b is >= a and < b, and a..=b is >= a and <= b.
Types
T name matches a value whose type is T (or derives from it, or implements it) and gives it as a T in name. Without a name, T only tests. Primitives, generic types and interfaces work:
import System;
Kind(any? x) : str => x switch
{
null => "null",
i32 n => "i32 " + n,
str s => "text " + s,
List<i32> l => "a list of " + l.Count,
_ => "something else",
};
Main()
{
Console.WriteLine(Kind(null));
Console.WriteLine(Kind(4));
Console.WriteLine(Kind("hi"));
Console.WriteLine(Kind(new List<i32>()));
Console.WriteLine(Kind(2.5));
str? maybe = "x";
if (maybe is str text)
Console.WriteLine(text.Length);
if (maybe is not null)
Console.WriteLine("has a value");
}
larva run
null
i32 4
text hi
a list of 0
something else
1
has a value
- A type pattern on a nullable value matches only a value that is not null, so
maybe is str textboth tests for null and names the string. - A type the value can never have is AN2088 or AN2089 (
a i32 is never a str). - Inside a pattern,
?after a type is not read as a nullable type (sox is T ? a : bis a conditional). Test nullable values withnullandnot null.
Positions
(p, q, …) matches the positions of the value, in order, and T(p, q, …) first tests the type T. The positions of a value are:
- the fields of a tuple (
Item1,Item2…); - the fields a
record classorrecord valuestores, in their order; - the fields of a
value, in their order; - the
&mutparameters of a methodDeconstruct, for other classes.
import System;
public record value Point
{
public:
i32 X;
i32 Y;
new(i32 X, i32 Y);
}
Where(Point p) : str => p switch
{
(0, 0) => "origin",
Point(0, var y) => "on the Y axis at " + y,
(var x, 0) => "on the X axis at " + x,
{ X: > 0, Y: > 0 } => "first quadrant",
_ => "elsewhere",
};
Main()
{
Console.WriteLine(Where(new Point(0, 0)));
Console.WriteLine(Where(new Point(0, 5)));
Console.WriteLine(Where(new Point(3, 0)));
Console.WriteLine(Where(new Point(1, 2)));
Console.WriteLine(Where(new Point(-1, 2)));
Console.WriteLine((1, "a") is (1, _));
}
larva run
origin
on the Y axis at 5
on the X axis at 3
first quadrant
elsewhere
true
A class gets positions by declaring Deconstruct with one &mut parameter per position. References need the borrow checker (borrowcheck: warn or enforce; see Memory):
public class Size
{
public:
i32 W;
i32 H;
new(i32 W, i32 H);
Deconstruct(&mut i32 w, &mut i32 h) { w = W; h = H; }
}
Size s = new Size(2, 3);
if (s is (2, var h))
Console.WriteLine(h); // 3
The wrong number of positions is AN2135, and a type without positions is AN2136.
Properties
{ Name: p, … } matches fields and properties by name; with a type before it, T { … } also tests the type. Each sub-pattern is any pattern, so they nest:
if (order is { Customer: { Country: "AR" }, Total: > 100 })
Ship(order);
A name the type does not have is AN2137.
when
A when condition after an arm's pattern adds a test. The variables the pattern names can be used in it:
import System;
public base class Shape { }
public class Circle : Shape
{
public:
f64 Radius;
new(f64 Radius);
}
public class Rect : Shape
{
public:
f64 W;
f64 H;
new(f64 W, f64 H);
}
Describe(Shape s) : str => s switch
{
Circle c when c.Radius > 10 => "a big circle",
Circle c => "a circle of radius " + c.Radius,
Rect { W: 0 } or Rect { H: 0 } => "a flat rectangle",
Rect r => "a rectangle " + r.W + "x" + r.H,
_ => "something else",
};
Main()
{
Console.WriteLine(Describe(new Circle(20)));
Console.WriteLine(Describe(new Circle(2)));
Console.WriteLine(Describe(new Rect(0, 4)));
Console.WriteLine(Describe(new Rect(2, 3)));
}
larva run
a big circle
a circle of radius 2
a flat rectangle
a rectangle 2x3
Variables
A name declared by a pattern (T name, var name) is a new local. In is, it is set where the test is true, so it can be used after && and in the if it guards:
if (n is var m && m > 5)
Console.WriteLine(m);
In a switch arm, it is seen in the arm's when condition and its body.
Order and exhaustiveness
Arms are tried in order, and the first that matches wins: put the more specific ones first.
The compiler does not check that a switch covers every value:
- a switch statement where no arm matches does nothing;
- a switch expression where no arm matches stops the program with
larva panic: null reference(exit code 101).
End a switch expression with _ => … unless its arms surely cover every value.
Editar esta página en GitHub Reportar un problema