4. diel - Typový systém druhýkrát - Dátové typy v C# .NET
V predchádzajúcom cvičení, Riešené úlohy k 1.-3. lekcii C# .NET, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
Teraz sa na dátové typy pozrieme viac zblízka a vysvetlíme si, kedy ktorý použiť. Dnešná lekcia bude veľmi teoretická, ale o to praktickejšia bude tá budúca. Na konci lekcie si vytvoríme zopár jednoduchých ukážok.
C# rozoznáva dva druhy dátových typov: hodnotové a referenčné.
Hodnotové dátové typy
Premenné hodnotového dátového typu si dokážeme jednoducho predstaviť. Môže sa jednať napr. o číslo alebo znak. V pamäti je jednoducho uložená priamo hodnota a my k tejto hodnote môžeme z programu priamo pristupovať. Slovo priamo som nepoužil dvakrát len náhodou. V tomto C# kurze sa budeme venovať výhradne týmto premenným.
Celočíselné dátové typy
Pozrime sa teraz na tabuľku všetkých vstavaných celočíselných
dátových typov v .NET. Všimnite si typ int
, ktorý už poznáme
z minula:
Dátový typ | Rozsah | Veľkosť | .NET typ |
---|---|---|---|
sbyte | –128 až 127 | 8 bitov | System.SByte |
byte | 0 až 255 | 8 bitov | System.Byte |
short | –32 768 až 32 767 | 16 bitov | System.Int16 |
ushort | 0 až 65 535 | 16 bitov | System.UInt16 |
int | –2 147 483 648 až 2 147 483 647 | 32 bitov | System.Int32 |
uint | 0 až 4 294 967 295 | 32 bitov | System.UInt32 |
long | –9 223 372 036 854 775 808 až 9 223 372 036 854 775 807 | 64 bitov | System.Int64 |
ulong | 0 až 18 446 744 073 709 551 615 | 64 bitov | System.UInt64 |
Všetky tieto šialené čísla z tabuľky si pamätať nemusíte, vo Visual Studiu vám takmer vždy pomôže nástroj IntelliSense. Keď budete písať daný dátový typ a počkáte, nástroj nad ním ukáže bublinu:
V dokumentácii dodávanej k Visual Studiu prípadne tieto údaje nájdete podrobnejšie. Do dokumentácie sa dostanete tak, že napíšete konkrétny dátový typ, označíte ho a stlačíte F1.
Asi vás napadá otázka, prečo máme toľko možných typov na uloženie
čísla. Odpoveď je jednoduchá: záleží na jeho veľkosti. Čím väčšie
číslo je, tým viac spotrebuje pamäte. Pre vek užívateľa teda zvolíme
byte
, pretože sa určite nedožije viac ako 255 rokov. Predstavte
si databázu milióna užívateľov nejakého systému. Keď zvolíme miesto
byte
int
, bude zaberať 4x viac miesta. Naopak keď
budeme mať funkciu na výpočet faktoriálu, ťažko nám bude stačiť rozsah
integeru, a preto použijeme long
.
Všimnime si, že niektoré typy začínajú na u
. Sú takmer
rovnaké ako ich dvojníci bez u
, len neumožňujú záporné
hodnoty a tým pádom môžu na kladnú časť uložiť 2x vyššiu hodnotu.
Týmto typom sa hovorí unsigned, klasickým
signed.
.NET typ je názov danej štruktúry v .NET knižniciach. My používame tzv. aliasy, aby bola práca jednoduchšia. Môžeme teda napísať:
int a = 10;
V skutočnosti si C# tento kód preberie ako:
System.Int32 a = 10;
My budeme samozrejme používať aliasy, od toho tam sú
Nad výberom dátového typu nemusíte veľmi premýšľať a väčšinou sa
používa jednoducho int
. Typ riešte iba v prípade, keď sú
premenné v nejakom poli (všeobecne kolekcii) a je ich teda viac. Potom sa
oplatí zaoberať sa pamäťovými nárokmi. Tabuľky sem dávame skôr pre
úplnosť. Medzi typy samozrejme funguje už spomínaná implicitná konverzia,
môžeme teda priamo priradiť int
do premennej typu
long
a podobne bez toho, aby sme niečo konvertovali.
Desatinné čísla
U desatinných čísel je situácia trochu jednoduchšia, máme na výber iba
dva dátové typy. Samozrejme sa líšia opäť v rozsahu hodnoty, ďalej však
ešte v presnosti (vlastne počtu desatinných miest). Typ double
má už podľa názvu dvojnásobnú presnosť oproti float
:
Dátový typ | Rozsah | Presnosť | .NET typ |
---|---|---|---|
float | +−1.5 * 10−45 až +−3.4 * 1038 | 7 čísel | System.Single |
double | +−5.0 * 10−324 až +−1.7 * 10308 | 15–16 čísel | System.Double |
Vzhľadom na to, že desatinné čísla sú v počítači uložené v dvojkovej sústave, dochádza k určitej strate presnosti. Odchýlka je síce takmer zanedbateľná, ale keď budete programovať napr. finančný systém, nepoužívajte tieto dátové typy na uchovanie peňazí, mohlo by dôjsť k malým odchýlkam.
Keď do premennej typu float
chceme dosadiť hodnotu priamo v
zdrojovom kóde, musíme použiť sufix F
, pri double
sufix D
(pri double
ho môžeme vypustiť, pretože je
východiskový desatinných typ):
float f = 3.14F; double d = 2.72;
Ako desatinný separátor používame v zdrojovom kóde vždy bodku, nehľadiac na to, aké máme vo Windows regionálne nastavenia.
Ďalšie vstavané dátové typy
Pozrime sa na ďalšie dátové typy, ktoré nám .NET ponúka:
Dátový typ | Rozsah | Veľkosť/Presnosť | .NET typ |
---|---|---|---|
char | U+0000 až U+ffff | 16 bitov | System.Char |
decimal | +–1.0 * 10−28 až +–7.9 * 1028 | 28–29 čísel | System.Decimal |
bool | true nebo false | 8 bitov | System.Boolean |
char
Typ char
nám reprezentuje jeden znak, na rozdiel od typu
string
, ktorý reprezentoval celý reťazec char
.
Znaky v C# píšeme do apostrofov. Apostrof '
píšeme na
slovenskej klávesnici pomocou Shift a klávesy vedľa
Enter (u niektorých klávesníc je to klávesa nad Enter,
u iných pred ním):
Deklarujme si teda premennú typu char
obsahujúcu nejaký
znak:
char c = 'A';
Typ char
patrí v podstate do celočíselných premenných
(obsahuje číselný kód znaku), ale je logickejšie uviesť ho tu. Typ
char
nám vracia napr. metóda Console.ReadKey()
.
decimal
Typ decimal
rieši problém ukladania desatinných čísel v
binárnej podobe, ukladá totiž číslo vnútorne podobne ako text. Používa
sa teda na uchovanie peňažných hodnôt. Ku všetkým ďalším matematickým
operáciám s desatinnými číslami použijeme float
alebo
double
. Na zápis decimal
hodnoty opäť používame
sufix, a síce m
:
decimal m = 3.14159265358979323846m;
bool
Dátový typ bool
nadobúda dve hodnoty: true
(pravda) a false
(nepravda). Budeme ho používať najmä vtedy,
keď sa dostaneme k podmienkam. Do premennej typu bool
je možné
uložiť ako priamo hodnotu true
/ false
, tak aj
logický výraz. Skúsme si jednoduchý príklad:
{CSHARP_CONSOLE}
bool b = false;
bool expression = (15 > 5);
Console.WriteLine(b);
Console.WriteLine(expression);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
False
True
V ukážke sme použili znak >
. Znaky
>
a <
píšeme na slovenskej klávesnici pomocou
Pravého ALT a nasledujúcich klávesov:
Výrazy píšeme do zátvoriek. Vidíme, že výraz nadobúda hodnotu
true
(pravda), pretože 15
je naozaj väčší ako
5
. Od výrazov je to už len krok k podmienkam, na ktoré sa
pozrieme nabudúce.
Referenčné dátové typy
K referenčným typom sa dostaneme až pri objektovo orientovanom
programovaní, kde si tiež vysvetlíme zásadné rozdiely. Zatiaľ budeme
pracovať len s tak jednoduchými typmi, že rozdiel nepoznáme. Zatiaľ sa
uspokojíme so znalosťou, že referenčné typy sú zložitejšie ako tie
hodnotové. Jeden takýto typ už poznáme, je ním string
. Možno
vás napadá, že string
nemá nijako obmedzenú dĺžku. Je to
tým, že s referenčnými typmi sa v pamäti pracuje inak.
Typ string
má na sebe množstvo naozaj užitočných metód.
Niektoré si teraz preberieme a vyskúšame:
String
StartsWith()
,
EndsWith()
a Contains()
Môžeme sa jednoducho opýtať, či reťazec začína, končí alebo či
obsahuje určitý podreťazec (substring). Podreťazcom myslíme časť
pôvodného reťazca. Všetky tieto metódy budú ako parameter brať samozrejme
podreťazec a vracať hodnoty typu bool
(true
/
false
). Zatiaľ na výstup nevieme reagovať, ale poďme si ho
aspoň vypísať:
{CSHARP_CONSOLE}
string s = "Rhinopotamus";
Console.WriteLine(s.StartsWith("rhin"));
Console.WriteLine(s.EndsWith("tamus"));
Console.WriteLine(s.Contains("pot"));
Console.WriteLine(s.Contains("lol"));
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
False
True
True
False
Vidíme, že všetko funguje podľa očakávania. Prvý výraz samozrejme neprešiel vďaka tomu, že reťazec v skutočnosti začína veľkým písmenom.
ToUpper()
a ToLower()
Rozlišovanie veľkých a malých písmen môže byť niekedy na obtiaž.
Veľakrát sa budeme potrebovať opýtať na prítomnosť podreťazca tak, aby
nezáležalo na veľkosti písmen. Situáciu môžeme vyriešiť pomocou metód
ToUpper()
a ToLower()
, ktoré vracajú reťazec vo
veľkých a v malých písmenách. Uveďme si reálnejší príklad, než je
Rhinopotamus. V premennej budeme mať riadok konfiguračného súboru, ktorý
písal používateľ. Keďže sa na vstupy od používateľov nemožno
spoľahnúť, musíme sa snažiť eliminovať možné chyby, tu napr. s
veľkými písmenami:
{CSHARP_CONSOLE}
string config = "Fullscreen shaDows autosave";
config = config.ToLower();
Console.WriteLine("Will the game run in fullscreen?");
Console.WriteLine(config.Contains("fullscreen"));
Console.WriteLine("Will shadows be turned on?");
Console.WriteLine(config.Contains("shadows"));
Console.WriteLine("Will sound be turned off?");
Console.WriteLine(config.Contains("nosound"));
Console.WriteLine("Would the player like to use autosave?");
Console.WriteLine(config.Contains("autosave"));
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
Will the game run in fullscreen?
True
Will shadows be turned on?
True
Will sound be turned off?
False
Would the player like to use autosave?
True
Vidíme, že sme schopní zistiť prítomnosť jednotlivých slov v reťazci tak, že si najskôr reťazec prevedieme celý na malé písmená (alebo na veľké) a potom kontrolujeme prítomnosť slova len malými (alebo veľkými) písmenami. Takto by mimochodom mohlo skutočne vyzerať jednoduché spracovanie nejakého konfiguračného skriptu.
Trim()
, TrimStart()
a TrimEnd()
Problémom vo vstupoch od užívateľa môže byť aj diakritika. C# ale našťastie pracuje plne v UTF-8, nestane sa nám teda, že by sa diakritika nejako skomolila. Ďalšou nástrahou môžu byť medzery a všeobecne všetky tzv. biele znaky, ktoré nie sú vidieť, ale môžu nám uškodiť. Všeobecne môže byť dobré tzv. trimovať všetky vstupy od užívateľa. Môžeme trimovať buď okolo celého reťazca, alebo len biele znaky pred ním a za ním. Prezradíme, že pri parsovacích funkciách C# trimuje zadaný reťazec automaticky, kým s ním začne pracovať. Odstránené sú iba neviditeľné znaky okolo reťazca, napr. medzery medzi slovami zostanú. Skúste si v nasledujúcej aplikácii pred číslo a za číslo zadať niekoľko medzier:
{CSHARP_CONSOLE}
Console.WriteLine("Enter a number:");
string s = Console.ReadLine();
Console.WriteLine("Here's what you originally wrote: " + s);
Console.WriteLine("Your text after the trim function: " + s.Trim());
int a = int.Parse(s);
Console.WriteLine("I converted the text you entered to a number. Here it is: " + a);
Console.ReadKey();
{/CSHARP_CONSOLE}
Replace()
Asi najdôležitejšou metódou na type string
je nahradenie
určitej jeho časti iným textom. Ako parametre zadáme dvoch podreťazcov:
jeden, ktorý chceme nahradzovať, a druhý, ktorým prvý chceme nahradiť.
Metóda vráti nový string
, v ktorom prebehlo nahradenie. Keď
daný podreťazec metóda nenájde, vráti pôvodný reťazec.
V nasledujúcej ukážke použijeme v texte mriežku #
. Tá sa
na slovenskej klávesnici píše pomocou Pravého Alt a klávesu
X:
A teraz si už skúsme nahradiť podreťazec metódou
Replace()
:
{CSHARP_CONSOLE}
string s = "Java is the best!";
s = s.Replace("Java", "C#");
Console.WriteLine(s);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
C# is the best!
Format()
Format()
je veľmi užitočná metóda, ktorá nám umožňuje
vkladať do samotného textového reťazca zástupné značky. Tie sú
reprezentované ako číslo v zložených zátvorkách. Prvým číslom je
0
. Ako ďalšie parametre metódy nasledujú v tomto poradí
hodnoty, ktoré sa majú do textu namiesto značiek vložiť. Všimnime si, že
sa metóda nevolá na konkrétne premenné (presnejšie inštanciu, viď
ďalšie lekcie), ale priamo na type string
.
Zložené zátvorky (ľavú a pravú) píšeme na slovenskej klávesnici pomocou Pravého Alt a klávesy B pre ľavú, resp. N pre pravú:
Skúsme si teda použiť metódu Format()
na vloženie
niekoľkých premenných do premennej typu string
:
{CSHARP_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
string s = string.Format("When we add up {0} and {1}, we get {2}", a, b, c);
Console.WriteLine(s);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikácia
When we add up 10 and 20, we get 30
Konzola sama vie prijímať text v takomto formáte, môžeme teda napísať:
{CSHARP_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
Console.WriteLine("When we add up {0} and {1}, we get {2}", a, b, c);
Console.ReadKey();
{/CSHARP_CONSOLE}
Toto je veľmi užitočná a prehľadná cesta, ako zostavovať reťazce, a
určite sa ju oplatí mnohokrát použiť namiesto bežnej konkatenácie pomocou
operátora +
, pokiaľ nebazírujeme na vysokej rýchlosti.
Interpolácia reťazcov
Pokiaľ chceme do reťazca v C# na určité miesta vložiť nejaké
premenné, môžeme okrem zástupných znakov {0}
a pod. zapísať
premenné aj priamo do reťazca obalením názvu premennej do zložených
zátvoriek. Takýto reťazec potom musíme predsadiť znakom $
, aby
C# vedel, že v zložených zátvorkách má očakávať premenné a nejedná sa
o bežný text:
int a = 10; int b = 20; int c = a + b; Console.WriteLine($"When we add up {a} and {b}, we get {c}"); Console.ReadKey();
Na klávesnici znak dolára $
napíšeme pomocou
pravého Alt a písmena ô:
Výstup programu:
Konzolová aplikácia
When we add up 10 and 20, we get 30
Táto funkcionalita je podporovaná iba v nových verziách C# a zatiaľ ju nepodporuje náš online kompiler.
Podobne môžeme namiesto premennej vložiť aj výraz. Takáto funkcionalita sa nám často hodí pri výpise. Skúsme si tiež rovno sčítať čísla priamo vo výraze:
int a = 10; int b = 20; Console.WriteLine($"When we add up {a} and {b}, we get {a + b}"); Console.ReadKey();
Výstup programu:
Konzolová aplikácia
When we add up 10 and 20, we get 30
PadLeft()
a
PadRight()
Ako posledný si spomenieme metódy, ktoré nám k textu naopak medzery
pridajú Na čo je to dobré?
Predstavme si, že máme 100 premenných a budeme ich chcieť usporiadať do
tabuľky. Text upravíme pomocou metódy PadRight()
s parametrom
šírky stĺpca, teda napr. 20 znakov. Pokiaľ bude mať text len 12 znakov,
vypíše sa zaň 8 medzier, aby mal veľkosť 20. Podobne metóda
PadLeft()
by vypísala 8 medzier pred neho. Keďže zatiaľ nemáme
znalosti na vytvorenie takejto tabuľky, budeme si metódy len pamätať a
vyskúšame si ich ďalej v C# kurze.
Vlastnosť Length
Posledná, ale najdôležitejšia vlastnosť (pozor, nie metóda) je
Length
, teda dĺžka. Vracia celé číslo, ktoré predstavuje
počet znakov v reťazci. Za vlastnosti nepíšeme zátvorky, pretože nemajú
parametre.
{CSHARP_CONSOLE}
Console.WriteLine("Type in your name:");
string name = Console.ReadLine();
Console.WriteLine("Your name is {0} characters long.", name.Length);
Console.ReadKey();
{/CSHARP_CONSOLE}
Je toho ešte veľa na vysvetľovanie a existujú ďalšie dátové typy, ktoré sme neprebrali.
V nasledujúcom cvičení, Riešené úlohy k 4. lekcii C# .NET, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.