• Datové typy specifikují množiny přípustných
    • hodnot – co lze do datového typu uložit.
      • Např.: do int lze uložit celá čísla ve specifikovaném rozsahu
    • operací – jak lze s datovými typy pracovat.
      • Např.: sčítání dvou celých čísel
  • Každý programovací jazyk definuje svá pravidla pro datové typy
  • Slouží k tomu, aby bylo jasné co je na dané paměti uloženo
  • Proměnná – pojmenované místo v paměti, do kterého lze uložit data
    • Proměnné vždy mají datový typ
    • Existují pravidla pro tvorbu validních názvů proměnných

Dělení jazyků dle typovosti

  • Silně typované – každá proměnná musí mít v době kompilace určen svůj datový typ
    • Určení může být buďto explicitní, nebo jej lze odvodit z kontextu (type-inference)
    • Př.: C, C#, Java
  • Slabě typované – datové typy jsou přítomné až v runtime
    • Datový typ není nutné explicitně specifikovat
    • Př.: JavaScript

Dělení datových typů

Dle struktury

  • Jednoduché datové typy – jedná se o základní (elementární) datové typy
    • Tvoří se z nich později komplexnější typy (viz. strukturované datové typy)
    • Př.: int, float, char
  • Strukturované (komplexní) datové typy – slouží k uložení jedné nebo více souvisejících hodnot
    • Mohou obsahovat jednoduché datové typy nebo jiné strukturované datové typy. Např. třída může obsahovat proměnné typu int a char a zároveň i proměnnou typu string nebo třída.
    • Př.: string, array, struct, class

Dělení strukturovaných datových typů

  • Homogenní
    • Všechny hodnoty mají stejný datový typ
    • Př.: int[] – všechny položky v poli jsou typu int
  • Heterogenní
    • Hodnoty mají různé datové typy
    • Př.: struct nebo class – mohou obsahovat vlastnosti a členské proměnné, jejichž typy se mohou lišit např. int Age a string Name

Dle ukládání dat v paměti

  • Hodnotové datové typy
    • uloženy v paměti s názvem zásobník (stack)
    • velmi rychlý přístup a rychlé operace plynoucí z toho, že není nutná jakákoliv alokace/dealokace paměti
  • Referenční datové typy
    • uloženy v paměti s názvem halda (heap)
    • nutnost řešení alokací

Dle změnitelnosti hodnot

  • Mutable – hodnotu je možné kdykoliv změnit
    • Např.: int
  • Immutable – hodnotu není možné změnit
    • Toto omezení je hlídáno kompilátorem
    • Např.: string

Konverze datových typů

Konverze datových typů slouží k převodu jednoho datového typu na jiný.

Typy konverze

Konverzi lze dělit na dva typy:

  • Implicitní
  • Explicitní

Implicitní konverze

  • Dochází k ní automaticky bez nutnosti jakéhokoliv zásahu vývojáře
  • Podporována pouze ve chvíli, kdy nehrozí žádné problémy (např. podtečení, přetečení…)
  • Př.: Mějme proměnnouint x = 7; a provedeme přiřazení hodnoty do proměnné s datovým typem long long y = x;.
  • Do long je možné uložit jakýkoliv int, takže se provede automatická (implicitní) konverze na int na long

Explicitní

  • Vývojářem vynucená konverze
  • Tento typ není možné, aby kompilátor odhalil sám (např. z důvodu, že je přesný datový typ znám až za běhu programu – např. u polymorfismu)
  • Někdy je to také využíváno, když je potřebné obejít kontroly při kompilaci
  • Např.: Nechť je dána proměnná long x = 7; a je známo, že do ní program ukládá hodnoty v rozsahu {1, 2, .., 100}. Všechny tyto hodnoty lze uložit i do proměnné typu int, ale kompilátor bude hlásit chybu, že může dojít k podtečení. Pomocí explicitní konverze tuto konverzi vynutíme int y = (int) x;
  • Typy explicitní konverze:
    • (název_typu) – pokud se nepovede provést konverzi, tak vyhodí výjimku
    • Klíčové slovíčko as – pokud se nepovede provést konverzi, tak vrátí null
      • funguje pouze pro referenční nebo nullable typy
    • Pattern matching – pokud se konverze povede, tak je uložena hodnota do nové proměnné
object objInt = 42;
object objStr = "123.45";
 
// 1. Explicitní konverze pomocí ()
int intValue = (int)objInt;
Console.WriteLine($"(int) přetypování: {intValue}");
 
// 2. Explicitní konverze pomocí 'as'
string? strValue = objStr as string;
if (strValue != null)
{
	Console.WriteLine($"Přetypování pomocí 'as': {strValue}");
}
 
// 3. Pattern matching pomocí 'is'. Hodnota je pak uložena v proměnné s názvem 's'
if (objStr is string s)
{
	double parsed = double.Parse(s);
	Console.WriteLine($"Vzorové přiřazení a parsování na double: {parsed}");
}

Přetečení a podtečení

  • Přetečení (overflow) a podtečení (underflow) jsou pojmy označující chyby v programu, které jsou způsobené překročením povoleného rozsahu hodnot datového typu.
  • Týká se to hlavně číselných hodnot
  • Přetečení ani podtečení při běhu nevyhazuje běžně výjimky, takže je důležité jim předcházet.

Příklad:

  • Datový typ byte – má rozsah 0 až 255
byte a = 255;
a += 1; // přetečení
Console.WriteLine(a); // Výstup: 0
 
byte b = 0;
b -= 1; // podtečení
Console.WriteLine(b); // Výstup: 255

Checked a unchecked

Checked blok slouží k detekci přetečení i podtečení. Pokud k některému z nich dojde, provede se vyhození výjimky OverflowException. Opakem checked je unchecked, což je i výchozí nastavení běhového prostředí – tedy všechno je defaultně unchecked.

checked
{
   byte c = 255;
   c += 1; // vyhodí výjimku OverflowException
}
 
// alternativně:
int d = checked(2147483647 + 1); // OverflowException

Klíčové slovo var

Jedná se o klíčové slovo pro implicitní typování. Znamená to, že kompilátor sám odvodí konkrétní datový typ proměnné podle hodnoty, kterou jí přiřadíš při deklaraci.

var cislo = 10;         // kompilátor určí typ int
var jmeno = "Pepa";     // kompilátor určí typ string
var seznam = new List<string>(); // kompilátor určí typ List<string>

Pravidla pro práci s var

  1. Nutné přiřazení hodnoty při deklaraci – kompilátor musí hned vědět, jaký typ z toho má udělat.
  2. Typ je pevně daný – po odvození už proměnnou nelze změnit na jiný typ.
  3. Nelze jej použít jako návratový typ nebo typ parametru metody.

Kdy ho využít?

  1. Když je typ zřejmý z pravé strany přiřazení: var pocet = 42;
  2. Při práci s anonymními typy: var osoba = new { Jmeno = "Eva", Vek = 30 };
  3. Při složitých typech: var slovnik = new Dictionary<string, List<int>>();

Kdy ho naopak nepoužít?

Pokud to snižuje čitelnost kódu – někdy je lepší uvést typ přímo, aby bylo jasné, co proměnná obsahuje.

// Jaký datový typ má result?
var result = GetUserData();
 
// Lepší možnost:
UserData result = GetUserData();