Společnost ARM představila platformu Arm Lumex s Arm C1 CPU Cluster a Arm Mali G1-Ultra GPU pro vlajkové chytré telefony a počítače nové generace.
Unicode Consortium, nezisková organizace koordinující rozvoj standardu Unicode, oznámila vydání Unicode 17.0. Přidáno bylo 4 803 nových znaků. Celkově jich je 159 801. Přibylo 7 nových Emoji.
Apple představil (YouTube) telefony iPhone 17 Pro a iPhone 17 Pro Max, iPhone 17 a iPhone Air, sluchátka AirPods Pro 3 a hodinky Watch Series 11, Watch SE 3 a Watch Ultra 3.
Realtimová strategie Warzone 2100 (Wikipedie) byla vydána ve verzi 4.6.0. Podrobný přehled novinek, změn a oprav v ChangeLogu na GitHubu. Nejnovější verzi Warzone 2100 lze již instalovat také ze Snapcraftu a Flathubu.
Polské vývojářské studio CD Projekt Red publikovalo na Printables.com 3D modely z počítačové hry Cyberpunk 2077.
Organizátoři konference LinuxDays 2025 vydali program a zároveň otevřeli registrace. Akce se uskuteční 4. a 5. října na FIT ČVUT v pražských Dejvicích, kde vás čekají přednášky, workshopy, stánky a spousta šikovných lidí. Vstup na akci je zdarma.
Uživatelé komunikátoru Signal si mohou svá data přímo v Signalu bezpečně zálohovat a v případě rozbití nebo ztráty telefonu následně na novém telefonu obnovit. Zálohování posledních 45 dnů je zdarma. Nad 45 dnů je zpoplatněno částkou 1,99 dolaru měsíčně.
Server Groklaw, zaměřený na kauzy jako právní spory SCO týkající se Linuxu, skončil před 12 lety, resp. doména stále existuje, ale web obsahuje spam propagující hazardní hry. LWN.net proto v úvodníku připomíná důležitost zachovávání komunitních zdrojů a upozorňuje, že Internet Archive je také jen jeden.
Jakub Vrána vydal Adminer ve verzi 5.4.0: "Delší dobu se v Admineru neobjevila žádná závažná chyba, tak jsem nemusel vydávat novou verzi, až počet změn hodně nabobtnal."
V Německu slavnostně uvedli do provozu (en) nejrychlejší počítač v Evropě. Superpočítač Jupiter se nachází ve výzkumném ústavu v Jülichu na západě země, podle německého kancléře Friedricha Merze otevírá nové možnosti pro trénování modelů umělé inteligence (AI) i pro vědecké simulace. Superpočítač Jupiter je nejrychlejší v Evropě a čtvrtý nejrychlejší na světě (TOP500). „Chceme, aby se z Německa stal národ umělé inteligence,“ uvedl na
… více »
1. Metody, alias funkce
2. Třídy
2.1 Objektově orientovaný přístup
2.2 Definice tříd
2.3 Proměnné instance, inicializace
2.4 Přístupové metody
2.5 Řízení přístupu
2.6 Dědičnost
2.7 Proměnné třídy
Společně s tím, jak náš kód poroste, si brzy začneme všímat určitých úseků, které se budou v našem programu až příliš často opakovat. Zcela zjednodušeně, vytváříme-li například matematickou aplikaci, tak takové věci, jako je výpočet faktoriálu nebo třeba obvodu kruhu, využijeme poměrně často.
Dokola opisovat stále tentýž kód je nejen únavné, ale především nepraktické. Vymyslíme-li totiž v budoucnu efektivnější algoritmus nebo nedej bože zjistíme, že v něm máme chybu, budeme v důsledku odsouzeni k tomu důkladně projít celý zdrojový kód, který může čítat i desetitisíce řádků.
Moderní programovací jazyky (a Ruby není výjimkou) za tímto účelem nabízejí použití tzv. funkcí, kterým se v případě objektových jazyků říká metody. Obecný zápis definice metody vypadá takto:
def název(parametr_1, parametr_2, …) příkazy return návratová_hodnota end
Konvence říká, že názvy metod začínají malým písmenem. Definice se
uvozuje klíčovým slovem def
, v závorce následuje výčet
proměnných, jejichž prostřednictvím budou metodě předány hodnoty, vzájemně oddělené čárkou. V těle metody je zapsán samotný kód, za klíčovým slovem
return
je uvedena návratová hodnota. Definici uzavírá klíčové
slovo end
.
Ačkoli se metody obvykle uvádějí v definici tříd, jak si ostatně zanedlouho ukážeme, lze je uvádět i samostatně jako klasické funkce v procedurálních jazycích. V souboru se pak jejich definice zapisují před samotným kódem.
Pozapomeňme na chvíli na existenci vhodnější Math.sqrt()
a
zkusme si napsat metodu na výpočet druhé odmocniny ze zadaného čísla sami.
Ta by mohla vypadat například takto:
irb(main):001:0> def odmocnina(cislo) irb(main):002:1> return cislo**(1.0/2) irb(main):003:1> end => nil
K uvedení do chodu je třeba metodu odněkud z programu zavolat:
irb(main):004:0> odmocnina(256) => 16.0
Metody jsou volány svým jménem. V závorce jsou jim předány hodnoty,
které jsou následně přiřazeny lokálním proměnným v jejich těle – v
našem případě tedy platí, že cislo
= 256.
Jelikož metoda vrací hodnotu, lze ji postavit na pravou stranu přiřazení:
irb(main):005:0> vysledek = odmocnina(16) => 4.0 irb(main):006:0> puts vysledek 4.0 => nil
Pojďme si naši definici trochu rozšířit; řekněme, že chceme mít možnost počítat libovolnou odmocninu, nejen druhou. Toho zcela intuitivně docílíme přidáním druhého parametru. Zároveň by se nám ale líbilo, abychom tento parametr nemuseli uvádět v případě, že nám druhá odmocnina stačí. Jak na to?
Návrháři programovacích jazyků si lenost programátorů dobře uvědomují, a tak Ruby umožňuje v definici specifikovat implicitní hodnoty:
irb(main):007:0> def odmocnina(cislo, exponent=2) irb(main):008:1> return cislo**(1.0/exponent) irb(main):009:1> end => nil irb(main):010:0> odmocnina(16, 4) => 2.0 irb(main):011:0> odmocnina(16) => 4.0
Parametry s implicitními hodnotami musí být v definici vždy vpravo a
nelze je prokládat, jinak by nebylo možné zajistit správné přiřazení.
Definice def pitomost(x=4, y, z=2)
je tedy nesmyslná a
chybná.
Rekurze je možnost volat metodu z ní samotné a je silným nástrojem funkcionálních jazyků. V Ruby je nicméně možná také:
irb(main):012:0> def faktorial(n) irb(main):013:1> if n == 0 irb(main):014:2> return 1 irb(main):015:2> else irb(main):016:2* return n * faktorial(n - 1) irb(main):017:2> end irb(main):018:1> end => nil
Algoritmus slouží k výpočtu faktoriálu daného čísla. Je-li hodnota n nenulová, vynásobí se výsledkem volání metody s hodnotou n - 1. Je-li nulová, dojde k navrácení čísla 1 a rozvoj je ukončen. Tímto způsobem tak dosáhneme zcela intuitivního výpočtu, např. 6! = 6 * 5 * 4 * 3 * 2 * 1 = 720. Že to opravdu funguje ověříme snadno:
irb(main):019:0> faktorial(6) => 720
S rekurzí je nicméně třeba nakládat obezřetně, některé výpočty totiž mohou být značně paměťově náročné.
Pro úplnost ještě uvedu, že v definici metod lze vynechat také klíčové
slovo return
a psát tak např. jen:
def odmocnina(cislo) cislo**(1.0/2) end
Osobně však doporučuji se tomuto zkrácení pokud možno vyhnout, k přehlednosti totiž rozhodně nepřispívá.
Než přejdeme k vysvětlení samotné práce s třídami a objekty, bylo by více než vhodné si na tomto místě povědět, co to objektově orientované programování (OOP) vlastně je. Vzhledem k zaměření a rozsahu tohoto seriálu není možné se do detailů věnovat všem jeho aspektům a ani se o to nebudu pokoušet. Existují povolanější a podstatně obsáhlejší zdroje, které se touto problematikou zabývají, a myslíte-li to s programováním vážně, vřele doporučuji si je do budoucnosti prostudovat.
Máte-li už s programováním nějaké předchozí zkušenosti a objektově orientovaný přístup znáte, můžete následující odstavce bez obav přeskočit a přejít rovnou k podkapitole 2.2 Definice tříd.
S rozvojem výpočetní techniky se vyvíjely také programovací jazyky, a to především směrem k větší srozumitelnosti. Současně s nimi se měnily také přístupy ke psaní počítačových programů.
Poměrně dlouhou dobu bylo (a dodnes je) uznávaným modelem tzv. procedurální programování. Program sestává z dat, která jsou uchovávána prostřednictvím proměnných, a procedur, které s těmito daty pracují. Přístup rozdělení jednotlivých ucelených úkonů do samostatných procedur je poměrně efektivní a nepochybně umožnil rozvoj i velmi složitých aplikací (linuxové jádro je celé napsáno v procedurálním jazyce C). Typicky procedurálním jazykem je např. Pascal.
Objektově orientovaný přístup se snaží ještě více přiblížit strukturu programu lidskému myšlení a vnímání reálného světa. Člověk o okolním světě (většinou) neuvažuje jako o sadě proměnných a procedur, ale jako o objektech. Tento přístup umožňuje nejen o problémech přemýšlet a pojímat je jako reálné věci, ale také objekty z jednotlivých objektů skládat, ba dokonce vlastnosti dědit. Díky přístupovým metodám je pak možné ochránit data před nechtěným přepsáním a vnitřní implementace skrýt.
Pokud si některá tvrzení z předchozího odstavce nedokážete představit, pusťte je z hlavy. Vše si názorně ukážeme v následujících kapitolách.
Stejně jako je Aris pes a já jsem člověk, tak i jednotlivé objekty jsou
vždy konkrétními instancemi nějaké třídy. Třída samotná se skládá z
proměnných a metod a její definice je uvozena klíčovým slovem
class
. Konvencí je začínat názvy tříd velkým písmenem:
irb(main):020:0> class Pes irb(main):021:1> def zastekej irb(main):022:2> puts "Haf, haf!" irb(main):023:2> end irb(main):024:1> end => nil
Konkrétní instanci vytvoříme prostřednictvím metody
new
:
irb(main):025:0> aris = Pes.new => #<Pes:0xb7d1308c>
Nyní již můžeme s nově vytvořenou instancí pracovat:
irb(main):026:0> aris.zastekej Haf, haf! => nil
Ponechme prosím stranou absenci jakékoli užitečnosti takovéto třídy. Mějte na paměti, že jde pouze o jednoduchou ukázku na vysvětlení základních principů; postupy zde naučené lze stejně tak dobře aplikovat na komplikované algoritmické úlohy, v rámci přístupnosti a srozumitelnosti se však spokojíme s jednodušší variantou.
Dosud jsme si ukázali, jak definovat metody třídy. K uchovávání hodnot v
rámci jedné instance slouží tzv. proměnné instance a jsou to lokální
proměnné společné všem jejím metodám. Od běžných proměnných se liší tím, že
jejich názvy začínají znakem @
:
rb(main):027:0> class Pes irb(main):028:1> def initialize(jmeno, rasa) irb(main):029:2> @jmeno = jmeno irb(main):030:2> @rasa = rasa irb(main):031:2> end irb(main):032:1> def info irb(main):033:2> return "#{@jmeno} je #{@rasa}." irb(main):034:2> end irb(main):035:1> end => nil
Nadefinovali jsme si dvě proměnné instance (@jmeno
a
@rasa
) a dvě metody (initialize
a
info
).
initialize
je standardní název pro tzv. inicializační
metodu, která umožňuje předání hodnot instanci už při jejím vytvoření.
Na rozdíl od jiných metod se nevolá přímo, ale prostřednictvím již známé
metody new
:
irb(main):036:0> mujPes = Pes.new("Aris", "Border terier") => #<Pes:0xb7ca120c @jmeno="Aris", @rasa="Border terier">
Z návratové hodnoty je patrné, že zadané parametry byly skutečně předány
patřičným proměnným instance. Ověřit si to můžeme také zavoláním
muj_pes.info
.
Možná vás napadlo, že pomocí tečkové notace by se dal vypsat obsah proměnné instance přímo. Když to ale vyzkoušíme, obdržíme následující chybové hlášení:
irb(main):037:0> mujPes.jmeno NoMethodError: undefined method `jmeno' for #<Pes:0xb7c9d6fc @jmeno="Aris" , @rasa="Border terier"> from (irb):37 from :0
O nic úspěšnější nebudeme ani v případě, že zkusíme zadat
mujPes.@jmeno
. Toto chování je dalším aspektem objektového
přístupu – k práci s proměnnými slouží příslušné metody, což nejen
výrazně omezuje možné zavlečení chyby, ale zároveň také skrývá vnitřní
postupy.
Používáme-li například modul Math
, většinou nás nezajímá,
jak je vnitřně implementován. Co potřebujeme vědět je, jaké prostředky nám
poskytuje a jak se s nimi pracuje. Výhodou tohoto přístupu je také to, že
vnitřní implementace jednotlivých metod pak můžeme měnit bez toho, aby byl
jakkoli zasažen kód, který s danou třídou pracuje.
Definice třídy o obohacená o přístupové metody by tak mohla vypadat např. takto:
irb(main):038:0> class Pes irb(main):039:1> def initialize(jmeno, rasa) irb(main):040:2> @jmeno = jmeno irb(main):041:2> @rasa = rasa irb(main):042:2> end irb(main):043:1> def jmeno irb(main):044:2> return @jmeno irb(main):045:2> end irb(main):046:1> def rasa irb(main):047:2> return @rasa irb(main):048:2> end irb(main):049:1> end => nil
V uvedeném příkladu jsou přístupové metody pojmenovány stejně jako
proměnné instance, což umožňuje intuitivní přístup k nim, někteří
programátoři však upřednostňují pojmenování typu vypisJmeno
a
nastavJmeno
. Výběr je opět na vás, nicméně vhodné je zůstat v
rámci programu konzistentní.
Výše uvedená definice má jednu nevýhodu: stále nám neumožňuje do
proměnných zapisovat. Abychom zachovali výše zavedený způsob, nadefinujeme
si metodu pro ukládání do proměnné @jmeno
následujícím
způsobem:
irb(main):050:0> class Pes irb(main):051:1> def initialize(jmeno, rasa) irb(main):052:2> @jmeno = jmeno irb(main):053:2> @rasa = rasa irb(main):054:2> end irb(main):055:1> def jmeno irb(main):056:2> return @jmeno irb(main):057:2> end irb(main):058:1> def rasa irb(main):059:2> return @rasa irb(main):060:2> end irb(main):061:1> def jmeno=(noveJmeno) irb(main):062:2> @jmeno = noveJmeno irb(main):063:2> end irb(main):064:1> end => nil
Nyní můžeme s proměnnou pracovat, jako bychom k ní měli přímý přístup:
irb(main):065:0> mujPes = Pes.new("Aris", "Border terier") => #<Pes:0xb7cd1e0c @rasa="Border terier", @jmeno="Aris"> irb(main):066:0> mujPes.jmeno # puvodni jmeno => "Aris" irb(main):067:0> mujPes.jmeno = "Cassie" # prirazeni => "Cassie" irb(main):068:0> mujPes.jmeno # nove jmeno => "Cassie"
Jak vidíte, autor třídy má nad proměnnými plnou kontrolu a je jen na něm, které z nich a do jaké míry zpřístupní. Tato vlastnost má však jeden nepříjemný důsledek – díky přístupovým metodám se i takto triviální definice protáhla na nepříjemně velký počet řádků. Ruby proto nabízí elegantní zkratku:
irb(main):069:0> class Pes irb(main):070:1> def initialize(jmeno, rasa) irb(main):071:2> @jmeno = jmeno irb(main):072:2> @rasa = rasa irb(main):073:2> end irb(main):074:1> attr_reader :jmeno, :rasa irb(main):075:1> attr_writer :jmeno irb(main):076:1> end => nil
Tento příklad je naprostým ekvivalentem předcházejícího. Příkaz
attr_reader
vytvoří k vybraným proměnným metody pro čtení a
attr_writer
pro zápis. Názvy proměnných přitom začínají
dvojtečkou (nikoli zavináčem!) a jsou od sebe odděleny čárkami.
Už víme, že proměnné instance jsou považovány za soukromé a chceme-li k nim mít přístup „z venčí“, je třeba nadefinovat příslušné metody. To nám umožňuje nejen měnit způsob, jakým je s proměnnými vnitřně nakládáno, ale také rozhodnout, ke kterým proměnným vůbec přístup umožníme.
Ve složitějších třídách často pracujeme s metodami, které jsou volány jinými metodami, zároveň však neočekáváme jejich volání mimo definici třídy. Ruby rozlišuje tři druhy metod:
Pes
, mohou si k těmto metodám navzájem přistupovat. Tyto
metody však nejsou dostupné ani z instancí jiných tříd, ani z jiných
částí programu.Které metody jsou jakého druhu můžeme explicitně stanovit
prostřednictvím klíčových slov public
, protected
a private
:
irb(main):077:0> class Kruh irb(main):078:1> def initialize(polomer) # implicitne verejna irb(main):079:2> @polomer = polomer irb(main):080:2> @PI = 3.14159 irb(main):081:2> end irb(main):082:1> private # nasleduji soukrome irb(main):083:1> def obvod irb(main):084:2> return 2 * @PI * @polomer irb(main):085:2> end irb(main):086:1> def obsah irb(main):087:2> return @PI * @polomer**2 irb(main):088:2> end irb(main):089:1> public # nasleduji verejne irb(main):090:1> def parametry irb(main):091:2> return "polomer:\t" + @polomer.to_s + irb(main):092:2* "\nobvod:\t\t" + obvod.to_s + irb(main):093:2* "\nobsah:\t\t" + obsah.to_s + "\n" irb(main):094:2> end irb(main):095:1> end => nil
Druhou možností je rozlišovat druh metod až v závěru. V našem případě bychom tedy na konec připsali:
public :parametry private :obvod, :obsah
Volba je opět na vás. A že to doopravdy funguje, ověříme snadno:
irb(main):096:0> k = Kruh.new(5) => #<Kruh:0xb7ced378 @PI=3.14159, @polomer=5> irb(main):097:0> puts k.parametry polomer: 5 obvod: 31.4159 obsah: 78.53975 => nil irb(main):098:0> k.obvod NoMethodError: private method `obvod' called for #<Kruh:0xb7ced378 @PI=3.1 4159, @polomer=5> from (irb):98 from :0
Může se stát, že nám možnosti určité třídy přestanou dostačovat. Dědičnost je způsob, jak přejmout metody a proměnné původní třídy a umožnit jejich rozšíření bez nutnosti původní třídu opisovat. Toto je obzvláště výhodné také v případě, že vnitřní implementaci původní třídy neznáme.
Zkusme si nadefinovat novou třídu Stene
, která je v zásadě
speciálním případem třídy Pes
. Štěně je bezpochyby taky pes,
ale na rozdíl od většiny svých slušně vychovaných příbuzných disponuje
jedním nešvarem, a to tím, že rozkouše, na co přijde, obzvláště když mu
rostou zoubky. Definice by potom mohla vypadat nějak takto:
irb(main):099:0> class Stene<Pes irb(main):100:1> def rozkousej(predmet) irb(main):101:2> return "#{predmet} je na cucky!" irb(main):102:2> end irb(main):103:1> end => nil
irb(main):104:0> mujPes = Stene.new("Cassie", "Yorksirsky terier") => #<Stene:0xb7cf91b4 @rasa="Yorksirsky terier", @jmeno="Cassie"> irb(main):105:0> mujPes.jmeno => "Cassie" irb(main):106:0> mujPes.rozkousej("Dalkovy ovladac") => "Dalkovy ovladac je na cucky!"
Budeme-li chtít třídě přidat nové vlastnosti, pravděpodobně budeme muset
zasáhnout také do metody initialize
. Změny chování některé z
děděných metod docílíme její novou definicí, opisovat však celý její obsah
je přinejmenším nepohodlné. Naštěstí lze dědit také obsah přepisované
metody:
irb(main):107:0> class Stene<Pes irb(main):108:1> def initialize(jmeno, rasa, vek) irb(main):109:2> super(jmeno, rasa) irb(main):110:2> @vek = vek irb(main):111:2> end irb(main):112:1> attr_reader :vek irb(main):113:1> attr_writer :vek irb(main):114:1> end => nil
irb(main):115:0> mujPes = Stene.new("Cassie", "Yorksirek", "6 mesicu") => #<Stene:0xb7cd9d8c @rasa="Yorksirek", @jmeno="Cassie", @vek="6 mesicu"> irb(main):116:0> mujPes.jmeno => "Cassie" irb(main):117:0> mujPes.vek => "6 mesicu"
Vedle proměnných instance nabízí Ruby ještě tzv. proměnné
třídy, které jsou společné všem jejím instancím. Jejich názvy začínají
znaky @@
a uvádí se mimo těla definic metod, zpravidla na
začátku definice třídy před metodou initialize
.
V následujícím příkladu si nadefinujeme proměnnou třídy
@@pocet
, která bude uchovávat informace o počtu vytvořených
instancí:
irb(main):118:0> class Pes irb(main):119:1> @@pocet = 0 # promenna tridy irb(main):120:1> def initialize irb(main):121:2> @@pocet += 1 # pripocitame novou instanci irb(main):122:2> end irb(main):123:1> def pocet irb(main):124:2> return @@pocet # informace o aktualnim stavu irb(main):125:2> end irb(main):126:1> end => nil
Snadno ověříme, že to skutečně funguje:
irb(main):127:0> prvniPes = Pes.new => #<Pes:0xb7ceac18> irb(main):128:0> prvniPes.pocet => 1 irb(main):129:0> druhyPes = Pes.new => #<Pes:0xb7ce3cd8> irb(main):130:0> prvniPes.pocet => 2
Nástroje: Tisk bez diskuse
Tiskni
Sdílej:
nejaky velky projekty napsany v RubyZatím nikdo nic extra velkýho neprásknul, ale už jen ve standardní distribuci Ruby by mělo být ~420000 řádků Ruby. To mi přijde celkem dost.
ne nejakej web franty fuky
attr_accessor:
? Potom se do tý proměnný dá i zapisovat a nemusí se na to dělat extra metody stylem:
class Pes def initialize(jmeno) @jmeno = jmeno end def name return #{@jmeno} end def setName(jmeno) @jmeno = jmeno end endMísto toho se použije
class Pes attr_accessor: jmeno def initialize(jmeno) @jmeno = jmeno end end