Pattern matching
Forms that compile (29)
Section titled “Forms that compile (29)”| Syntax | Description | Note |
|---|---|---|
switch (n) { case 1: … } | Branch with a statement | |
case 1: | Branch with a statement (numbers) | |
n switch { 1 => 10, _ => 0 } | Branch with an expression | Matching an int requires a _ => case. |
m switch { Mode.A => 1, _ => 0 } | Branch on an enum | The _ => case can’t be omitted even when the cases are exhaustive. |
s switch { "a" => 1, _ => 0 } | Branch on a string | |
s is Dot | Checking the type | |
s is Line l | Checking the type and binding | |
case Dot: | Type in a case label | A form that branches on the type of a union value. |
s switch { Dot d => …, Line l => … } | Exhaustive union cases | |
n is 1 | Matching a constant | |
s is null | Matching against null | |
s is "a" | Matching a string constant | |
m is Mode.On | Matching an enum constant | |
n is < 30 | Relational matching | |
n is >= 0 and <= 100 | Combining conditions (and pattern) | |
Next() is >= 0 and <= 100 | How many times the left side is evaluated | Writing two conditions still calls Next() only once. |
n is 3 or 4 | Combining conditions (or pattern) | |
s is not null | Negation | |
n is int and (< 0 or > 100) | Precedence with parentheses | |
n is var x | A binding that always matches | |
h is { V: 1 } | Matching a member value | Only a struct or record you declared yourself can go on the left. |
h is { V: > 0 } | Matching a nested member value | |
k switch { < 30 => … } | Relational case (expression) | |
k switch { 3 or 4 => … } | Case with an or pattern (expression) | |
k switch { int n when n > 3 => … } | Case condition (when, expression) | |
n switch { var v when v > 0 => … } | Condition after binding | |
case < 30: | Relational case (statement) | |
case 3 or 4: | Case with an or pattern (statement) | |
case int n when n > 3: | Case condition (when, statement) |
Forms that don’t compile (5)
Section titled “Forms that don’t compile (5)”| Syntax | Description | Error | Reason | Alternative |
|---|---|---|---|---|
p is (1, 2) | Deconstruct and match by position | TUKI0001 | not yet | Match by member value ({ Item1: 1 }) |
value is int (on a type argument’s value) | Apply a pattern to a type argument’s value | TUKI0001 | not yet | Rewrite it without using a type parameter |
s switch { Line l when … => … } | Attach a condition to a union type pattern | TUKI0001 | not yet | Move the condition into the case body, or split the case without when |
n switch { 1 => 10, 2 => 20 } | Omit the default case (int) | TUKI0001 | by design | Add _ =>. It can only be omitted for a union. |
m switch { Mode.A => 1, Mode.B => 2 } | Omit the default case (enum) | TUKI0001 | by design | Can’t be omitted even if the cases cover every value |
| Forms where the default case can be omitted | Union only. For int and enums, a _ => case is required even when the cases are exhaustive |
Forms where when can’t be attached | Only the type-pattern cases of a union. Value patterns and relational patterns accept it in both switch statements and expressions |
Branching on constants
Section titled “Branching on constants”Branch with a statement
Section titled “Branch with a statement”using UnityEngine;using Tsukimi;
public class PatSwitchStatement : TsukimiBehaviour{ void Start() { int n = 1; switch (n) { case 1: Debug.Log(10); break; // => 10 default: Debug.Log(0); break; } }}Branch with a statement (numbers)
Section titled “Branch with a statement (numbers)”using UnityEngine;using Tsukimi;
public class IsoSwStmtConst : TsukimiBehaviour{ void Start() { int k = 1; switch (k) { case 1: Debug.Log(1); break; default: Debug.Log(0); break; } // => 1 }}Branch with an expression
Section titled “Branch with an expression”A switch expression yields the value of the case that matched.
using UnityEngine;using Tsukimi;
public class PatDiscardArm : TsukimiBehaviour{ void Start() { int n = 1; int r = n switch { 1 => 10, _ => 0 }; Debug.Log(r); // => 10 }}Branch on an enum
Section titled “Branch on an enum”Enum constants can be written as cases.
using UnityEngine;using Tsukimi;
public enum Mode { A, B }
public class PatEnumConstant : TsukimiBehaviour{ void Start() { Mode m = Mode.A; int r = m switch { Mode.A => 1, _ => 0 }; Debug.Log(r); // => 1 }}Branch on a string
Section titled “Branch on a string”using UnityEngine;using Tsukimi;
public class PatStringConstant : TsukimiBehaviour{ void Start() { string s = "a"; int r = s switch { "a" => 1, _ => 0 }; Debug.Log(r); // => 1 }}Dispatching by type
Section titled “Dispatching by type”Checking the type
Section titled “Checking the type”Writing a type on the right of is only works for union and interface values.
using UnityEngine;using Tsukimi;
public abstract record Shape;public record Dot : Shape;public record Line(int Len) : Shape;
public class IsoIsTypeUnion : TsukimiBehaviour{ void Start() { Shape s = new Dot(); bool b = s is Dot; Debug.Log(b); // => true }}Checking the type and binding
Section titled “Checking the type and binding”using UnityEngine;using Tsukimi;
public abstract record Shape;public record Dot : Shape;public record Line(int Len) : Shape;
public class PtDeclaration : TsukimiBehaviour{ void Start() { Shape s = new Line(3); if (s is Line l) { Debug.Log(l.Len); } // => 3 }}Type in a case label
Section titled “Type in a case label”A type can be written in a case label too.
using UnityEngine;using Tsukimi;
public abstract record Shape;public record Dot : Shape;public record Line(int Len) : Shape;
public class PtTypeCase : TsukimiBehaviour{ void Start() { Shape s = new Dot(); switch (s) { case Dot: Debug.Log(0); break; default: Debug.Log(1); break; } // => 0 }}Exhaustive union cases
Section titled “Exhaustive union cases”Writing all the union’s cases lets you omit the _ => case.
using UnityEngine;using Tsukimi;
public abstract record Shape;public record Dot : Shape;public record Line(int Len) : Shape;
public class PtExhaustiveUnion : TsukimiBehaviour{ void Start() { Shape s = new Dot(); int v = s switch { Dot d => 0, Line l => l.Len }; Debug.Log(v); // => 0 }}Matching on value conditions
Section titled “Matching on value conditions”Matching a constant
Section titled “Matching a constant”using UnityEngine;using Tsukimi;
public class IsoIsConst : TsukimiBehaviour{ void Start() { int k = 1; bool b = k is 1; Debug.Log(b); // => true }}Matching against null
Section titled “Matching against null”using UnityEngine;using Tsukimi;
public class PtConstNull : TsukimiBehaviour{ void Start() { string s = null; if (s is null) { Debug.Log(1); } // => 1 }}Matching a string constant
Section titled “Matching a string constant”using UnityEngine;using Tsukimi;
public class PtConstString : TsukimiBehaviour{ void Start() { string s = "a"; if (s is "a") { Debug.Log(1); } // => 1 }}Matching an enum constant
Section titled “Matching an enum constant”using UnityEngine;using Tsukimi;
public enum Mode { Off, On }public class PtConstEnum : TsukimiBehaviour{ void Start() { Mode m = Mode.On; if (m is Mode.On) { Debug.Log(1); } // => 1 }}Relational matching
Section titled “Relational matching”using UnityEngine;using Tsukimi;
public class PtRelational : TsukimiBehaviour{ void Start() { int k = 1; if (k is < 30) { Debug.Log(1); } // => 1 }}Combining conditions (and pattern)
Section titled “Combining conditions (and pattern)”using UnityEngine;using Tsukimi;
public class PtAnd : TsukimiBehaviour{ void Start() { int k = 1; if (k is >= 0 and <= 100) { Debug.Log(1); } // => 1 }}How many times the left side is evaluated
Section titled “How many times the left side is evaluated”The left side of is is evaluated only once.
using UnityEngine;using Tsukimi;
public class PtAndOnce : TsukimiBehaviour{ int Next() { Debug.Log(9); // => 9 return 1; }
void Start() { if (Next() is >= 0 and <= 100) { Debug.Log(1); } // => 1 }}Combining conditions (or pattern)
Section titled “Combining conditions (or pattern)”using UnityEngine;using Tsukimi;
public class PtOr : TsukimiBehaviour{ void Start() { int k = 3; if (k is 3 or 4) { Debug.Log(1); } // => 1 }}Negation
Section titled “Negation”using UnityEngine;using Tsukimi;
public class PtNot : TsukimiBehaviour{ void Start() { string s = "a"; if (s is not null) { Debug.Log(1); } // => 1 }}Precedence with parentheses
Section titled “Precedence with parentheses”using UnityEngine;using Tsukimi;
public class PtParen : TsukimiBehaviour{ void Start() { int k = 1; if (k is int and (< 0 or > 100)) { Debug.Log(1); } }}A binding that always matches
Section titled “A binding that always matches”using UnityEngine;using Tsukimi;
public class PtVar : TsukimiBehaviour{ void Start() { int k = 1; if (k is var x) { Debug.Log(x); } // => 1 }}Matching a member value
Section titled “Matching a member value”Inside { }, write the member names and the values to match them against.
using UnityEngine;using Tsukimi;
public struct Holder { public int V { get; set; } }public class PtProperty : TsukimiBehaviour{ void Start() { Holder h = new Holder(); if (h is { V: 1 }) { Debug.Log(1); } }}Matching a nested member value
Section titled “Matching a nested member value”using UnityEngine;using Tsukimi;
public struct Holder { public int V { get; set; } }public class PtNested : TsukimiBehaviour{ void Start() { Holder h = new Holder(); if (h is { V: > 0 }) { Debug.Log(1); } }}Conditions on switch cases
Section titled “Conditions on switch cases”Relational case (expression)
Section titled “Relational case (expression)”using UnityEngine;using Tsukimi;
public class IsoSwExprRel : TsukimiBehaviour{ void Start() { int k = 1; int v = k switch { < 30 => 1, _ => 0 }; Debug.Log(v); // => 1 }}Case with an or pattern (expression)
Section titled “Case with an or pattern (expression)”using UnityEngine;using Tsukimi;
public class IsoSwExprOr : TsukimiBehaviour{ void Start() { int k = 3; int v = k switch { 3 or 4 => 1, _ => 0 }; Debug.Log(v); // => 1 }}Case condition (when, expression)
Section titled “Case condition (when, expression)”using UnityEngine;using Tsukimi;
public class IsoSwExprWhen : TsukimiBehaviour{ void Start() { int k = 5; int v = k switch { int n when n > 3 => n, _ => 0 }; Debug.Log(v); // => 5 }}Condition after binding
Section titled “Condition after binding”using UnityEngine;using Tsukimi;
public class R_wc : TsukimiBehaviour{ void Start() { int n = 1; int r = n switch { var v when v > 0 => 10, _ => 0 }; Debug.Log(r); // => 10 }}Relational case (statement)
Section titled “Relational case (statement)”using UnityEngine;using Tsukimi;
public class IsoSwStmtRel : TsukimiBehaviour{ void Start() { int k = 12; switch (k) { case < 30: Debug.Log(1); break; default: Debug.Log(0); break; } // => 1 }}Case with an or pattern (statement)
Section titled “Case with an or pattern (statement)”using UnityEngine;using Tsukimi;
public class IsoSwStmtOr : TsukimiBehaviour{ void Start() { int k = 4; switch (k) { case 3 or 4: Debug.Log(1); break; default: Debug.Log(0); break; } // => 1 }}Case condition (when, statement)
Section titled “Case condition (when, statement)”A case accepts the same matching forms in a switch statement and in a switch expression.
using UnityEngine;using Tsukimi;
public class IsoSwStmtWhen : TsukimiBehaviour{ void Start() { int k = 5; switch (k) { case int n when n > 3: Debug.Log(n); break; default: Debug.Log(0); break; } // => 5 }}