Porovnávání vzorů is
– výrazy a switch
operátory and
a ve not
or
vzorech
Výraz, příkaz switch a výraz switch použijete is
k porovnání vstupního výrazu s libovolným počtem charakteristik. C# podporuje více vzorů, včetně deklarace, typu, konstanty, relačního, vlastnosti, seznamu, var a zahození. Vzory lze kombinovat pomocí logických logických and
klíčových slov , or
a not
.
Následující výrazy a příkazy jazyka C# podporují porovnávání vzorů:
V těchto konstruktorech můžete spárovat vstupní výraz s některým z následujících vzorů:
- Vzor deklarace: Chcete-li zkontrolovat typ výrazu za běhu, a pokud je shoda úspěšná, přiřaďte výsledek výrazu deklarované proměnné.
- Typový vzor: Zkontrolujete typ výrazu za běhu. Zavedeno v jazyce C# 9.0.
- Konstantní vzor: Testuje, jestli se výsledek výrazu rovná zadané konstantě.
- Relační vzory: k porovnání výsledku výrazu se zadanou konstantou. Zavedeno v jazyce C# 9.0.
- Logické vzory: Testuje, jestli výraz odpovídá logické kombinaci vzorů. Zavedeno v jazyce C# 9.0.
- Vzor vlastností: k otestování, jestli vlastnosti nebo pole výrazu odpovídají vnořeným vzorům.
- Poziční vzor: dekonstruuje výsledek výrazu a otestuje, jestli se výsledné hodnoty shodují s vnořenými vzory.
var
pattern( vzor): pro spárování libovolného výrazu a přiřazení jeho výsledku k deklarované proměnné.- Zahodit vzor: aby se shodovaly s libovolným výrazem.
- Vzory seznamu: Testuje, jestli se sekvenční prvky shodují s odpovídajícími vnořenými vzory. Zavedeno v C# 11.
Logické vzory, vzory vlastností, umístění a seznamů jsou rekurzivní vzory. To znamená, že můžou obsahovat vnořené vzory.
Příklad použití těchto vzorů k vytvoření algoritmu řízeného daty najdete v tématu Kurz: Použití porovnávání vzorů k sestavení algoritmů řízených typem a daty.
Vzory deklarací a typů
Pomocí vzorů deklarací a typů můžete zkontrolovat, jestli je typ výrazu za běhu kompatibilní s daným typem. Pomocí vzoru deklarace můžete také deklarovat novou místní proměnnou. Když vzor deklarace odpovídá výrazu, je této proměnné přiřazen výsledek převedeného výrazu, jak ukazuje následující příklad:
object greeting = "Hello, World!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: hello, world!
}
Vzor deklarace s typem T
odpovídá výrazu, pokud výsledek výrazu není null a platí některé z následujících podmínek:
Typ běhu výsledku výrazu je
T
.Typ běhu výsledku výrazu se odvozuje od typu
T
, implementuje rozhraníT
nebo z něj existuje jiný implicitní převod odkazu naT
. Následující příklad ukazuje dva případy, kdy je tato podmínka pravdivá:var numbers = new int[] { 10, 20, 30 }; Console.WriteLine(GetSourceLabel(numbers)); // output: 1 var letters = new List<char> { 'a', 'b', 'c', 'd' }; Console.WriteLine(GetSourceLabel(letters)); // output: 2 static int GetSourceLabel<T>(IEnumerable<T> source) => source switch { Array array => 1, ICollection<T> collection => 2, _ => 3, };
V předchozím příkladu se při prvním volání
GetSourceLabel
metody první vzor shoduje s hodnotou argumentu, protože typint[]
běhu argumentu je odvozen od Array typu. Při druhém voláníGetSourceLabel
metody se typ List<T> běhu argumentu neodvozuje z Array typu, ale implementuje ICollection<T> rozhraní.Typ výsledku výrazu za běhu je typ hodnoty s možnou hodnotou null s podkladovým typem
T
.Existuje převod boxingu nebo unboxingu z typu run-time výsledku výrazu na typ
T
.
Následující příklad ukazuje poslední dvě podmínky:
int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
Console.WriteLine(a + b); // output: 30
}
Pokud chcete zkontrolovat pouze typ výrazu, můžete místo názvu proměnné použít zahození _
, jak ukazuje následující příklad:
public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}
public static class TollCalculator
{
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car _ => 2.00m,
Truck _ => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
}
Počínaje jazykem C# 9.0 můžete k tomuto účelu použít typový vzor, jak ukazuje následující příklad:
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car => 2.00m,
Truck => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
Podobně jako vzor deklarace odpovídá vzor typu výrazu, pokud výsledek výrazu není null a jeho typ za běhu splňuje některou z výše uvedených podmínek.
Pokud chcete zkontrolovat nenulovou hodnotu, můžete použít vzor negovanénull
konstanty, jak ukazuje následující příklad:
if (input is not null)
{
// ...
}
Další informace najdete v částech Vzor deklarace a Typ v poznámkách k návrhu funkce.
Konstantní vzor
Pomocí konstantního vzoru můžete otestovat, jestli se výsledek výrazu rovná zadané konstantě, jak ukazuje následující příklad:
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 12.0m,
2 => 20.0m,
3 => 27.0m,
4 => 32.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
V konstantním vzoru můžete použít libovolný konstantní výraz, například:
- celočíselný literál nebo číselný literál s plovoucí desetinou čárkou
- znak
- řetězcový literál.
- logická hodnota
true
nebofalse
- hodnota výčtu
- název deklarovaného pole const nebo local
null
Výraz musí být typ, který je převoditelný na konstantní typ, s jednou výjimkou: Výraz, jehož typ je Span<char>
nebo ReadOnlySpan<char>
může být spárován s konstantními řetězci v C# 11 a novějších verzích.
Pomocí konstantního vzoru zkontrolujte null
, jak ukazuje následující příklad:
if (input is null)
{
return;
}
Kompilátor zaručuje, že se při vyhodnocení výrazu x is null
nevyvolá žádný operátor ==
rovnosti přetížený uživatelem.
Počínaje jazykem C# 9.0 můžete pomocí negovanéhonull
vzoru konstanty zkontrolovat, jestli není null, jak ukazuje následující příklad:
if (input is not null)
{
// ...
}
Další informace najdete v části Konstantní vzor poznámky k návrhu funkce.
Relační vzory
Počínaje jazykem C# 9.0 použijete relační vzor k porovnání výsledku výrazu s konstantou, jak ukazuje následující příklad:
Console.WriteLine(Classify(13)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(2.4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
V relačním vzoru můžete použít libovolný z relačních operátorů<
, >
<=
nebo >=
. Pravá část relačního vzoru musí být konstantní výraz. Výraz konstanty může být typu integer, floating-point, char nebo enum .
Pokud chcete zkontrolovat, jestli je výsledek výrazu v určitém rozsahu, porovnáte ho se vzorem spojivekand
, jak ukazuje následující příklad:
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17))); // output: winter
static string GetCalendarSeason(DateTime date) => date.Month switch
{
>= 3 and < 6 => "spring",
>= 6 and < 9 => "summer",
>= 9 and < 12 => "autumn",
12 or (>= 1 and < 3) => "winter",
_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};
Pokud výsledek výrazu je null
nebo se nepodaří převést na typ konstanty převodem s možnou hodnotou null nebo unboxing, relační vzor neodpovídá výrazu.
Další informace najdete v části Relační vzory v poznámce k návrhu funkce.
Logické vzory
Počínaje jazykem C# 9.0 vytvoříte not
pomocí kombinátorů , and
a or
vzorů následující logické vzory:
Negace
not
vzor, který odpovídá výrazu, když negovaný vzor neodpovídá výrazu. Následující příklad ukazuje, jak můžete negovat konstantnínull
vzor a zkontrolovat, jestli výraz není null:if (input is not null) { // ... }
Konjunktiv
and
vzor, který odpovídá výrazu, pokud oba vzory odpovídají výrazu. Následující příklad ukazuje, jak můžete zkombinovat relační vzory a zkontrolovat, jestli je hodnota v určitém rozsahu:Console.WriteLine(Classify(13)); // output: High Console.WriteLine(Classify(-100)); // output: Too low Console.WriteLine(Classify(5.7)); // output: Acceptable static string Classify(double measurement) => measurement switch { < -40.0 => "Too low", >= -40.0 and < 0 => "Low", >= 0 and < 10.0 => "Acceptable", >= 10.0 and < 20.0 => "High", >= 20.0 => "Too high", double.NaN => "Unknown", };
Disjunktiv
or
vzor, který odpovídá výrazu, když některý ze vzorů odpovídá výrazu, jak ukazuje následující příklad:Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); // output: winter Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); // output: autumn Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); // output: spring static string GetCalendarSeason(DateTime date) => date.Month switch { 3 or 4 or 5 => "spring", 6 or 7 or 8 => "summer", 9 or 10 or 11 => "autumn", 12 or 1 or 2 => "winter", _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."), };
Jak ukazuje předchozí příklad, můžete opakovaně použít kombinátory vzorů ve vzoru.
Priorita a pořadí kontroly
Následující seznam uvádí kombinátory vzorů od nejvyšší priority po nejnižší:
not
and
or
Pokud chcete explicitně určit prioritu, použijte závorky, jak ukazuje následující příklad:
static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
Poznámka
Pořadí, ve kterém se vzory kontrolují, není definováno. V době běhu je možné nejprve zkontrolovat vnořené vzory or
a and
vzory zprava.
Další informace najdete v části Kombinátory vzorů v poznámce k návrhu funkce.
Vzor vlastnosti
Vzor vlastností můžete použít ke spárování vlastností výrazu nebo polí s vnořenými vzory, jak ukazuje následující příklad:
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Vzor vlastnosti odpovídá výrazu, pokud výsledek výrazu není null a každý vnořený vzor odpovídá odpovídající vlastnosti nebo poli výsledku výrazu.
Do vzoru vlastnosti můžete také přidat kontrolu typu za běhu a deklaraci proměnné, jak ukazuje následující příklad:
Console.WriteLine(TakeFive("Hello, world!")); // output: Hello
Console.WriteLine(TakeFive("Hi!")); // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' })); // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' })); // output: abc
static string TakeFive(object input) => input switch
{
string { Length: >= 5 } s => s.Substring(0, 5),
string s => s,
ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
ICollection<char> symbols => new string(symbols.ToArray()),
null => throw new ArgumentNullException(nameof(input)),
_ => throw new ArgumentException("Not supported input type."),
};
Vzor vlastnosti je rekurzivní vzor. To znamená, že jako vnořený vzor můžete použít libovolný vzor. Pomocí vzoru vlastnosti můžete spárovat části dat s vnořenými vzory, jak ukazuje následující příklad:
public record Point(int X, int Y);
public record Segment(Point Start, Point End);
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start: { Y: 0 } } or { End: { Y: 0 } };
Předchozí příklad používá dvě funkce dostupné v jazyce C# 9.0 a novější: or
kombinátor vzorů a typy záznamů.
Počínaje jazykem C# 10 můžete odkazovat na vnořené vlastnosti nebo pole v rámci vzoru vlastností. Tato funkce se označuje jako model rozšířených vlastností. Můžete například refaktorovat metodu z předchozího příkladu do následujícího ekvivalentního kódu:
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
Další informace najdete v části Model vlastností v poznámce k návrhu funkce a v poznámce k návrhu funkce rozšířených vzorů vlastností .
Tip
Můžete použít pravidlo stylu Model Zjednodušit (IDE0170) ke zlepšení čitelnosti kódu tím, že navrhnete místa pro použití rozšířených vzorů vlastností.
Poziční vzor
Poziční vzor slouží k dekonstrukci výsledku výrazu a porovnávání výsledných hodnot s odpovídajícími vnořenými vzory, jak ukazuje následující příklad:
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}
static string Classify(Point point) => point switch
{
(0, 0) => "Origin",
(1, 0) => "positive X basis end",
(0, 1) => "positive Y basis end",
_ => "Just a point",
};
V předchozím příkladu typ výrazu obsahuje Deconstruct metoda, která se používá k dekonstrukci výsledku výrazu. Můžete také porovnat výrazy typů řazené kolekce členů s pozičními vzory. Tímto způsobem můžete porovnat více vstupů s různými vzory, jak ukazuje následující příklad:
static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
=> (groupSize, visitDate.DayOfWeek) switch
{
(<= 0, _) => throw new ArgumentException("Group size must be positive."),
(_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
(>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
(>= 10, DayOfWeek.Monday) => 30.0m,
(>= 5 and < 10, _) => 12.0m,
(>= 10, _) => 15.0m,
_ => 0.0m,
};
Předchozí příklad používá relační a logické vzory, které jsou k dispozici v jazyce C# 9.0 a novějších.
Názvy prvků a Deconstruct
parametrů řazené kolekce členů můžete použít v pozičním vzoru, jak ukazuje následující příklad:
var numbers = new List<int> { 1, 2, 3 };
if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))
{
Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); // output: Sum of [1 2 3] is 6
}
static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)
{
int sum = 0;
int count = 0;
foreach (int number in numbers)
{
sum += number;
count++;
}
return (sum, count);
}
Poziční vzor můžete také rozšířit některým z následujících způsobů:
Přidejte kontrolu typu běhu a deklaraci proměnné, jak ukazuje následující příklad:
public record Point2D(int X, int Y); public record Point3D(int X, int Y, int Z); static string PrintIfAllCoordinatesArePositive(object point) => point switch { Point2D (> 0, > 0) p => p.ToString(), Point3D (> 0, > 0, > 0) p => p.ToString(), _ => string.Empty, };
Předchozí příklad používá poziční záznamy , které implicitně poskytují metodu
Deconstruct
.Použijte vzor vlastnosti v rámci pozičního vzoru, jak ukazuje následující příklad:
public record WeightedPoint(int X, int Y) { public double Weight { get; set; } } static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };
Zkombinujte dvě předchozí použití, jak ukazuje následující příklad:
if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p) { // .. }
Poziční vzor je rekurzivní vzor. To znamená, že jako vnořený vzor můžete použít libovolný vzor.
Další informace najdete v části Positional pattern (Poziční vzor ) poznámky k návrhu funkce.
var
Vzor
Vzor použijete ke spárování libovolného var
výrazu, včetně null
, a jeho výsledek přiřadíte nové místní proměnné, jak ukazuje následující příklad:
static bool IsAcceptable(int id, int absLimit) =>
SimulateDataFetch(id) is var results
&& results.Min() >= -absLimit
&& results.Max() <= absLimit;
static int[] SimulateDataFetch(int id)
{
var rand = new Random();
return Enumerable
.Range(start: 0, count: 5)
.Select(s => rand.Next(minValue: -10, maxValue: 11))
.ToArray();
}
Vzor var
je užitečný, když potřebujete dočasnou proměnnou v rámci logického výrazu, která bude obsahovat výsledek průběžných výpočtů. Vzor můžete použít var
také v případě, že potřebujete provést více kontrol v when
případě ochrany výrazu switch
nebo příkazu, jak ukazuje následující příklad:
public record Point(int X, int Y);
static Point Transform(Point point) => point switch
{
var (x, y) when x < y => new Point(-x, y),
var (x, y) when x > y => new Point(x, -y),
var (x, y) => new Point(x, y),
};
static void TestTransform()
{
Console.WriteLine(Transform(new Point(1, 2))); // output: Point { X = -1, Y = 2 }
Console.WriteLine(Transform(new Point(5, 2))); // output: Point { X = 5, Y = -2 }
}
V předchozím příkladu je vzor var (x, y)
ekvivalentní pozičnímu vzoru(var x, var y)
.
var
Ve vzoru je typem deklarované proměnné typ kompilace výrazu, který se shoduje se vzorem.
Další informace najdete v části Vzor var poznámky k návrhu funkce.
Zahodit vzor
Vzor zahození_
použijete, aby odpovídal libovolnému výrazu, včetně null
, jak je znázorněno v následujícím příkladu:
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); // output: 5.0
Console.WriteLine(GetDiscountInPercent(null)); // output: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); // output: 0.0
static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch
{
DayOfWeek.Monday => 0.5m,
DayOfWeek.Tuesday => 12.5m,
DayOfWeek.Wednesday => 7.5m,
DayOfWeek.Thursday => 12.5m,
DayOfWeek.Friday => 5.0m,
DayOfWeek.Saturday => 2.5m,
DayOfWeek.Sunday => 2.0m,
_ => 0.0m,
};
V předchozím příkladu se ke zpracování null
a jakékoli celočíselné hodnoty, která nemá odpovídající člen výčtu DayOfWeek , používá vzor zahození. To zaručuje, že switch
výraz v příkladu zpracuje všechny možné vstupní hodnoty. Pokud ve switch
výrazu nepoužíváte vzor zahození a žádný ze vzorů výrazu neodpovídá vstupu, modul runtime vyvolá výjimku. Kompilátor vygeneruje upozornění, pokud switch
výraz nezpracuje všechny možné vstupní hodnoty.
Vzor zahození nemůže být vzorem ve výrazu is
switch
ani příkazu. V těchto případech použijte vzor se zahozením, který odpovídá libovolnému výrazuvar
: var _
.
Další informace najdete v části Zahodit vzor poznámky k návrhu funkce.
Vzor v závorkách
Počínaje jazykem C# 9.0 můžete vložit závorky kolem libovolného vzoru. Obvykle to uděláte tak, že zvýrazníte nebo změníte prioritu v logických vzorcích, jak ukazuje následující příklad:
if (input is not (float or double))
{
return;
}
Vzory seznamů
Počínaje C# 11 můžete porovnat pole nebo seznam se sekvencí vzorů, jak ukazuje následující příklad:
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True
Jak ukazuje předchozí příklad, vzor seznamu je spárován, když je každý vnořený vzor spárován odpovídajícím prvkem vstupní sekvence. V rámci vzoru seznamu můžete použít libovolný vzor. Chcete-li porovnat libovolný prvek, použijte vzor zahození nebo, pokud chcete také zachytit element, vzor var, jak ukazuje následující příklad:
List<int> numbers = new() { 1, 2, 3 };
if (numbers is [var first, _, _])
{
Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.
Předchozí příklady odpovídají celé vstupní sekvenci se vzorem seznamu. Pokud chcete porovnat prvky pouze na začátku nebo/a na konci vstupní sekvence, použijte vzor ..
řezu, jak ukazuje následující příklad:
Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]); // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]); // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]); // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]); // False
Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]); // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]); // True
Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]); // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]); // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]); // False
Vzor řezu odpovídá nule nebo více prvků. Ve vzoru seznamu můžete použít maximálně jeden vzor řezu. Vzorek řezu se může zobrazit jenom ve vzoru seznamu.
Dílčípattern můžete také vnořit do vzoru řezu, jak ukazuje následující příklad:
void MatchMessage(string message)
{
var result = message is ['a' or 'A', .. var s, 'a' or 'A']
? $"Message {message} matches; inner part is {s}."
: $"Message {message} doesn't match.";
Console.WriteLine(result);
}
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB.
MatchMessage("apron"); // output: Message apron doesn't match.
void Validate(int[] numbers)
{
var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
Console.WriteLine(result);
}
Validate(new[] { -1, 0, 1 }); // output: not valid
Validate(new[] { -1, 0, 0, 1 }); // output: valid
Další informace najdete v poznámce k návrhu funkcí seznamů vzorů .
specifikace jazyka C#
Další informace najdete v následujících poznámkách k návrhu funkce:
- C# 7 – Porovnávání vzorů
- C# 8 – Rekurzivní porovnávání vzorů
- C# 9 – Aktualizace porovnávání vzorů
- C# 10 – Rozšířené vzory vlastností
- C# 11 – Vzory seznamů
- C# 11 – Shoda
Span<char>
vzoru u řetězcového literálu