Hlavní navigace

Užitečné funkce a makra ze standardní knihovny Rustu

Pavel Tišnovský

V dnešním článku se budeme zabývat funkcemi a makry ze standardní knihovny Rustu. Popíšeme si formátování zpráv, práci s proměnnými prostředí a zpracováním argumentů předaných na příkazovém řádku.

Obsah

1. Základní a alternativní formátování celočíselných hodnot

2. Šířka vypisovaných hodnot

3. Zarovnání hodnot: doleva, doprava, vycentrování

4. Výplň místa specifikovaným znakem

5. Vytištění znaménka a tisk počátečních nul

6. Nastavení přesnosti výpisu hodnot s plovoucí řádovou čárkou

7. Řízení šířky a přesnosti s využitím nepovinných argumentů

8. Celočíselné primitivní datové typy – základní funkce a metody

9. Prohození bajtů ve slovech, konverze mezi little a big endian

10. Bitové rotace a posuny celočíselných hodnot

11. Zjištění atributů hodnot s plovoucí řádovou čárkou

12. Proměnné prostředí vyhodnocované v době překladu

13. Proměnné prostředí vyhodnocované při běhu aplikace

14. Přečtení argumentů předaných na příkazové řádce

15. Repositář s demonstračními příklady

16. Odkazy na Internetu

1. Základní formátování celočíselných hodnot

V programovacím jazyku Rust mají vývojáři k dispozici velmi užitečné makro nazvané format!, které je možné použít pro převod prakticky libovolných hodnot na řetězec s možností specifikace způsobu formátování. Toto makro lze použít buď přímo nebo nepřímo v dalším makru pojmenovaném println!, které již důvěrně známe z předchozích částí tohoto seriálu. Toto makro používá stejný způsob zápisu formátovacího řetězce, pouze se po výpisu výsledného textu na standardní výstup navíc provede přidání znaku pro konec řádku (provede se odřádkování).

Formátovací řetězec se zapisuje způsobem, který se poněkud odlišuje od céčkovské funkce printf. Nejprve si ukažme, jakým způsobem je možné zvolit základ číselné soustavy při převodu celého čísla (se znaménkem či bez znaménka) na řetězec. Ve výchozím nastavení se použije desítková soustava, lze však zvolit i soustavu osmičkovou, hexadecimální (s malými či velkými písmeny pro cifry A až F) a nově taktéž soustavu binární. Každému číslu, které se má objevit ve výstupním řetězci/formátované zprávě, odpovídá obsah jedné dvojice složených závorek {} (pokud jsou závorky prázdné, odpovídá to výchozímu formátování a použití desítkové soustavy):

fn main() {
    let value = 42;
 
    println!("{}", value);
    println!("0{:o}", value);
    println!("0x{:x}", value);
    println!("0x{:X}", value);
    println!("0b{:b}", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

42
052
0x2a
0x2A
0b101010

Existuje i alternativní forma výpisu, v níž se do výsledného řetězce automaticky přidají i prefixy číselné soustavy (0o, 0×, 0b). Alternativní forma vyžaduje použití znaku # před specifikací číselné soustavy:

fn main() {
    let value = 42;
 
    println!("{}", value);
    println!("{:#o}", value);
    println!("{:#x}", value);
    println!("{:#X}", value);
    println!("{:#b}", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

42
0o52
0x2a
0x2A
0b101010

2. Šířka vypisovaných hodnot

Specifikovat je samozřejmě možné i šířku vypisovaných hodnot, ovšem s tím, že pokud je nutné hodnotu reprezentovat větším počtem znaků, než je zadaná šířka, bude se šířka ignorovat; viz druhý řádek (znak roury je zde použit jen pro vizuální zvýraznění šířky řetězce a nemá zde žádný specifický význam):

fn main() {
    let value = 42;
 
    println!("|{}|", value);
    println!("|{:1}|", value);
    println!("|{:10}|", value);
    println!("|{:20}|", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42|
|42|
|        42|
|                  42|

Šířku lze samozřejmě kombinovat se specifikací základu číselné soustavy, a to takto:

fn main() {
    let value = 42;
 
    println!("|{}|", value);
    println!("|{:1b}|", value);
    println!("|{:10b}|", value);
    println!("|{:20b}|", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42|
|101010|
|    101010|
|              101010|

Makrem println! je samozřejmě možné naformátovat a vypsat více hodnot:

fn main() {
    let value1 = 42;
    let value2 = 8080;
    println!("|{:10}|{:10}|", value1, value2);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|        42|      8080|

3. Zarovnání hodnot: doleva, doprava, vycentrování

V případě, že je hodnota naformátována na menší počet znaků, než by odpovídalo specifikaci šířky, lze zvolit způsob zarovnání. Podporováno je zarovnání doprava (znak >), doleva (znak <) a na střed (znak ^), samozřejmě s tím, že zarovnání na střed nemusí být přesné (lichý počet znaků versus sudá hodnota zarovnání a naopak):

fn main() {
    let value = 42;
 
    println!("|{}|", value);
    println!("|{:20}|", value);
    println!("|{:>20}|", value);
    println!("|{:<20}|", value);
    println!("|{:^20}|", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42|
|                  42|
|                  42|
|42                  |
|         42         |

Povšimněte si, že výchozí zarovnání numerických hodnot je doprava (druhý zvýrazněný řádek výpisu). Zkusme si však příklad upravit tak, že se namísto celočíselné hodnoty bude formátovat řetězec:

fn main() {
    let str = "hello";
 
    println!("|{}|", str);
    println!("|{:20}|", str);
    println!("|{:>20}|", str);
    println!("|{:<20}|", str);
    println!("|{:^20}|", str);
}

Na druhém řádku je patrné, že implicitní zarovnání řetězců je na levý okraj:

|hello|
|hello               |
|               hello|
|hello               |
|       hello        |

Explicitní určení zarovnání samozřejmě funguje stejně v obou případech, viz poslední tři řádky výpisu.

4. Výplň místa specifikovaným znakem

V některých případech může být užitečné použít při formátování výstupu namísto mezer odlišné znaky. I tato možnost je v programovacím jazyku Rust podporována, což je patrné z následujícího příkladu, v němž u numerických hodnot používáme pro výplň tečky a u řetězců podtržítka:

fn main() {
    let value = 42;
    println!("|{}|", value);
    println!("|{:10}|", value);
    println!("|{:.>10}|", value);
    println!("|{:.<10}|", value);
    println!("|{:.^10}|", value);
 
    println!("")
 
    let str = "hello";
    println!("|{}|", str);
    println!("|{:20}|", str);
    println!("|{:_>20}|", str);
    println!("|{:_<20}|", str);
    println!("|{:_^20}|", str);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42|
|        42|
|........42|
|42........|
|....42....|
 
|hello|
|hello               |
|_______________hello|
|hello_______________|
|_______hello________|

Další způsob použití:

fn main() {
    for i in 0..16 {
        println!("|{:.>10}|", 1 << i);
    }
}

Zpráva vypsaná po překladu a spuštění příkladu:

|.........1|
|.........2|
|.........4|
|.........8|
|........16|
|........32|
|........64|
|.......128|
|.......256|
|.......512|
|......1024|
|......2048|
|......4096|
|......8192|
|.....16384|
|.....32768|

5. Vytištění znaménka a tisk počátečních nul

Makra format! a println! rozeznávají ve formátovacím řetězci i znak +, kterým se vyžaduje explicitní výpis znaménka celočíselné hodnoty, a to i ve chvíli, kdy je hodnota kladná. Znak – je taktéž možné použít, ale prozatím se ignoruje, tj. nemá žádný speciální význam (na rozdíl od printf v céčku). Použití znaků + a – je jednoduché:

fn main() {
    let value1 =  42;
    let value2 = -42;
 
    println!("|{}|", value1);
    println!("|{:-10}|", value1);
    println!("|{:+10}|", value1);
    println!("|{}|", value2);
    println!("|{:-10}|", value2);
    println!("|{:+10}|", value2);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42|
|        42|
|       +42|
|-42|
|       -42|
|       -42|

Pokud je nutné do výpisu naformátovaných celočíselných hodnot doplnit nuly (ty nemění význam vypsané hodnoty), není nic jednoduššího než použít znak 0 před uvedením požadované šířky výpisu:

fn main() {
    let value1 =  42;
    let value2 = -42;
 
    println!("|{:-010}|", value1);
    println!("|{:+010}|", value1);
    println!("|{:-010}|", value2);
    println!("|{:+010}|", value2);
}

Zpráva vypsaná po překladu a spuštění příkladu:

|0000000042|
|+000000042|
|-000000042|
|-000000042|

Totéž platí i pro další základy číselných soustav:

fn main() {
    for i in 0..16 {
        println!("{:08b}", i);
    }
}

Zpráva vypsaná po překladu a spuštění příkladu:

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
00001010
00001011
00001100
00001101
00001110
00001111

6. Nastavení přesnosti výpisu hodnot s plovoucí řádovou čárkou

U hodnot s plovoucí řádovou čárkou je možné explicitně zvolit počet číslic za čárkou/tečkou, a to způsobem, který se používal již v céčku, tj. uvede se celková šířka čísla ve znacích a za tečkou pak počet desetinných míst. Opět je možná kombinace se specifikací zarovnání:

fn main() {
    let value = 42.5;
 
    println!("{}",        value);
    println!("{:10}",     value);
    println!("{:10.4}",   value);
    println!("{:+10}",    value);
    println!("{:+10.4}",  value);
    println!("{:^+10}",   value);
    println!("{:^+10.4}", value);
}

Zpráva vypsaná po překladu a spuštění příkladu:

42.5
      42.5
   42.5000
     +42.5
  +42.5000
  +42.5
 +42.5000

7. Řízení šířky a přesnosti s využitím nepovinných argumentů

Požadovaná šířka ve formátovacím řetězci se alternativně zadává i specifikací jména nepovinného parametru makra format! a println!. V následujícím příkladu je za znakem : namísto číselné hodnoty šířky specifikováno jméno width (ukončené dolarem), které musí odpovídat pojmenovanému parametru. Pokud je nutné použít zarovnání, zapíše se znak pro zarovnání před jméno parametru:

fn main() {
    let value = 42.5;
 
    for i in 1..20 {
        println!("|{:width$}|", value, width=i);
    }
 
    for i in 1..20 {
        println!("|{:^width$}|", value, width=i);
    }
}

Zpráva vypsaná po překladu a spuštění příkladu:

|42.5|
|42.5|
|42.5|
|42.5|
| 42.5|
|  42.5|
|   42.5|
|    42.5|
|     42.5|
|      42.5|
|       42.5|
|        42.5|
|         42.5|
|          42.5|
|           42.5|
|            42.5|
|             42.5|
|              42.5|
|               42.5|
|42.5|
|42.5|
|42.5|
|42.5|
|42.5 |
| 42.5 |
| 42.5  |
|  42.5  |
|  42.5   |
|   42.5   |
|   42.5    |
|    42.5    |
|    42.5     |
|     42.5     |
|     42.5      |
|      42.5      |
|      42.5       |
|       42.5       |
|       42.5        |

Zkusme si vytvořit složitější příklad, v němž se mění jak šířka výsledného čísla v řetězci, tak i počet desetinných míst. Povšimněte si, že ve formátovacím řetězci se jména nepovinných parametrů vždy ukončují znakem dolaru:

fn main() {
    let value = 0.5;
 
    for w in 1 .. 11 {
        println!("width={}", w);
        for p in 1 .. (w-1) {
            println!("|{:width$.precision$}|", value, width=w, precision=p);
        }
        println!("");
    }
}

Zpráva vypsaná po překladu a spuštění příkladu:

width=1
 
width=2
 
width=3
|0.5|
 
width=4
| 0.5|
|0.50|
 
width=5
|  0.5|
| 0.50|
|0.500|
 
width=6
|   0.5|
|  0.50|
| 0.500|
|0.5000|
 
width=7
|    0.5|
|   0.50|
|  0.500|
| 0.5000|
|0.50000|
 
width=8
|     0.5|
|    0.50|
|   0.500|
|  0.5000|
| 0.50000|
|0.500000|
 
width=9
|      0.5|
|     0.50|
|    0.500|
|   0.5000|
|  0.50000|
| 0.500000|
|0.5000000|
 
width=10
|       0.5|
|      0.50|
|     0.500|
|    0.5000|
|   0.50000|
|  0.500000|
| 0.5000000|
|0.50000000|

8. Celočíselné primitivní datové typy – základní funkce a metody

Další oblastí, kterou se dnes budeme zabývat, jsou metody dostupné pro vybrané primitivní datové typy. Začneme celočíselnými hodnotami, pro něž existují metody nazvané min_value() a max_value() vracející minimální a maximální hodnotu reprezentovatelnou daným celočíselným datovým typem. V následujícím příkladu se minimální a maximální hodnoty vypíšou pro všech osm celočíselných typů:

fn main() {
    println!("Type:      {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22}",
             "i8",
             "i16",
             "i32",
             "i64",
             "u8",
             "u16",
             "u32",
             "u64");
    println!("min_value: {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22}",
             i8::min_value(),
             i16::min_value(),
             i32::min_value(),
             i64::min_value(),
             u8::min_value(),
             u16::min_value(),
             u32::min_value(),
             u64::min_value());
    println!("max_value: {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22} {:>22}",
             i8::max_value(),
             i16::max_value(),
             i32::max_value(),
             i64::max_value(),
             u8::max_value(),
             u16::max_value(),
             u32::max_value(),
             u64::max_value());
}

Vypsaná tabulka odpovídá předpokládanému výsledku:

Type:                i8          i16          i32                    i64           u8          u16          u32                    u64
min_value:         -128       -32768  -2147483648   -9223372036854775808            0            0            0                      0
max_value:          127        32767   2147483647    9223372036854775807          255        65535   4294967295   18446744073709551615

(některé sloupce jsou pro přehlednost zmenšeny)

9. Prohození bajtů ve slovech, konverze mezi little a big endian

Mezi další užitečné metody u primitivních datových typů patří metoda swap_bytes() sloužící pro prohození všech bajtů ve slově (kromě u8 a i8) a dále metody from_le(), from_be(), to_le() a to_be(), které lze použít pro konverzi mezi nativní reprezentací čísla a formátem little endian a big endiann. Podle použité platformy mohou dvě z těchto funkcí vracet původní hodnotu. Příkladem může být platforma i386, u níž funkce from_le() vrátí původní číslo. Ostatně můžeme si to vyzkoušet:

fn main() {
    let value:u32 = 0xcafebabe;

    println!("{:x}", value);
    println!("{:x}", value.swap_bytes());
    println!("{:x}", u32::from_le(value));
    println!("{:x}", u32::from_be(value));
}

Na platformě i386 či x86–64 by se mělo vypsat:

cafebabe
bebafeca
cafebabe
bebafeca

10. Bitové rotace a posuny celočíselných hodnot

Zatímco bitové posuny jsou podporovány samotným jazykem díky operátorům << a >>, bitové rotace je nutné provést metodami nazvanými rotate_left() a rotate_right(). Pro lepší ilustraci budeme původní hodnotu, posunutou hodnotu i zrotovanou hodnotu vypisovat s formátováním 032b, tedy 32 bitů zarovnaných zleva nulami:

fn main() {
    let value:u32 = 3;
 
    println!("{:032b}", value);
 
    println!("");
    for rot in 0..10 {
        println!("{:032b}", value.rotate_left(rot));
    }
 
    println!("");
    for rot in 0..10 {
        println!("{:032b}", value.rotate_right(rot));
    }
 
    println!("");
    for rot in 0..10 {
        println!("{:032b}", value << rot);
    }
 
    println!("");
    for rot in 0..10 {
        println!("{:032b}", value >> rot);
    }
}

Zpráva vypsaná po překladu a spuštění příkladu:

00000000000000000000000000000011
 
00000000000000000000000000000011
00000000000000000000000000000110
00000000000000000000000000001100
00000000000000000000000000011000
00000000000000000000000000110000
00000000000000000000000001100000
00000000000000000000000011000000
00000000000000000000000110000000
00000000000000000000001100000000
00000000000000000000011000000000
 
00000000000000000000000000000011
10000000000000000000000000000001
11000000000000000000000000000000
01100000000000000000000000000000
00110000000000000000000000000000
00011000000000000000000000000000
00001100000000000000000000000000
00000110000000000000000000000000
00000011000000000000000000000000
00000001100000000000000000000000
 
00000000000000000000000000000011
00000000000000000000000000000110
00000000000000000000000000001100
00000000000000000000000000011000
00000000000000000000000000110000
00000000000000000000000001100000
00000000000000000000000011000000
00000000000000000000000110000000
00000000000000000000001100000000
00000000000000000000011000000000
 
00000000000000000000000000000011
00000000000000000000000000000001
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000

11. Zjištění atributů hodnot s plovoucí řádovou čárkou

Mnoho potenciálně důležitých informací je možné získat i pro primitivní datové typy s plovoucí řádovou čárkou, konkrétně pro typy „f32“ a „f64“. Především jsou dostupné informace o maximální hodnotě (která ještě není považována za nekonečno), o minimální hodnotě, o nejmenší kladné nenulové hodnotě a taktéž o způsobu reprezentace čísla (počet číslic, počet bitů pro uložení mantisy, největší a nejmenší exponent při dvojkovém i desítkovém vyjádření, radix atd.). Nesmíme zapomenout ani na speciální hodnoty: kladné a záporné nekonečno a NaN:

use std::f32;
 
fn main() {
    println!("Max          {}",    f32::MAX);
    println!("Min          {}",    f32::MIN);
    println!("Min pos      {}",    f32::MIN_POSITIVE);
    println!("");
    println!("+Infinity    {}",    f32::INFINITY);
    println!("-Infinity    {}",    f32::NEG_INFINITY);
    println!("NaN          {}",    f32::NAN);
    println!("");
    println!("Digits       {}",    f32::DIGITS);
    println!("Max exponent 10^{}", f32::MAX_10_EXP);
    println!("Min exponent 10^{}", f32::MIN_10_EXP);
    println!("Epsilon      {}",    f32::EPSILON);
    println!("");
    println!("Radix        {}",    f32::RADIX);
    println!("Digits       {}",    f32::MANTISSA_DIGITS);
    println!("Max exponent 2^{}",  f32::MAX_EXP);
    println!("Min exponent 2^{}",  f32::MIN_EXP);
}

Zpráva vypsaná po překladu a spuštění příkladu:

Max          340282350000000000000000000000000000000
Min          -340282350000000000000000000000000000000
Min pos      0.000000000000000000000000000000000000011754944
 
+Infinity    inf
-Infinity    -inf
NaN          NaN
 
Digits       6
Max exponent 10^38
Min exponent 10^-37
Epsilon      0.00000011920929
 
Radix        2
Digits       24
Max exponent 2^128
Min exponent 2^-125

Stejný příklad lze upravit pro typ „f64“:

use std::f64;
 
fn main() {
    println!("Max          {}",    f64::MAX);
    println!("Min          {}",    f64::MIN);
    println!("Min pos      {}",    f64::MIN_POSITIVE);
    println!("");
    println!("+Infinity    {}",    f64::INFINITY);
    println!("-Infinity    {}",    f64::NEG_INFINITY);
    println!("NaN          {}",    f64::NAN);
    println!("");
    println!("Digits       {}",    f64::DIGITS);
    println!("Max exponent 10^{}", f64::MAX_10_EXP);
    println!("Min exponent 10^{}", f64::MIN_10_EXP);
    println!("Epsilon      {}",    f64::EPSILON);
    println!("");
    println!("Radix        {}",    f64::RADIX);
    println!("Digits       {}",    f64::MANTISSA_DIGITS);
    println!("Max exponent 2^{}",  f64::MAX_EXP);
    println!("Min exponent 2^{}",  f64::MIN_EXP);
}

Zpráva vypsaná po překladu a spuštění příkladu:

Max          179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Min          -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Min pos      0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014
 
+Infinity    inf
-Infinity    -inf
NaN          NaN
 
Digits       15
Max exponent 10^308
Min exponent 10^-307
Epsilon      0.0000000000000002220446049250313
 
Radix        2
Digits       53
Max exponent 2^1024
Min exponent 2^-1021

12. Proměnné prostředí vyhodnocované v době překladu

V době překladu lze přistupovat k proměnným prostředí použitím makra env!. Překladač si v tomto případě hlídá, zda proměnná prostředí existuje a pokud tomu tak není, vypíše chybové hlášení. Hodnota proměnné je přečtena a zapsána do výsledného souboru, tj. namísto volání makra env! se bude ve výsledném kódu nacházet konstantní řetězec:

fn main() {
    println!("PATH:    {}", env!("PATH"));
    println!("HOME:    {}", env!("HOME"));
    println!("DISPLAY: {}", env!("DISPLAY"));
}

Zpráva vypsaná po překladu a spuštění příkladu:

PATH:    /home/tester/.npm/bin:/home/tester/.npm/bin:/home/tester/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/tester/bin:/home/tester/bin
HOME:    /home/tester
DISPLAY: :0.0

13. Proměnné prostředí vyhodnocované při běhu aplikace

Při běhu programu (runtime) je samozřejmě taktéž možné přistupovat k proměnným prostředí, dokonce je to ještě užitečnější, než v příkladu předchozím. Ovšem v tomto případě se nepoužívá makro, ale funkce env::var(). Tato funkce vrací typ Result popsaný minule, takže lze snadno zjistit, zda proměnná existuje či nikoli:

use std::env;
 
fn print_env_var(name:&str) {
    match env::var(name) {
        Ok(val) => println!("{}: {:?}", name, val),
        Err(e)  => println!("couldn't interpret {}: {}", name, e),
    }
}
 
fn main() {
    print_env_var("PATH");
    print_env_var("HOME");
    print_env_var("DISPLAY");
    print_env_var("SPECIAL");
}

Zpráva vypsaná po překladu a spuštění příkladu:

PATH: "/home/tester/.npm/bin:/home/tester/.npm/bin:/home/tester/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/tester/bin:/home/tester/bin"
HOME: "/home/tester"
DISPLAY: ":0.0"
couldn't interpret SPECIAL: environment variable not found

Snadno lze získat i iterátor se všemi proměnnými prostředí. Iterace nad jmény i hodnotami proměnných probíhá takto:

use std::env;
 
fn main() {
    for (key, value) in env::vars() {
        println!("{}: {}", key, value);
    }
}

14. Přečtení argumentů předaných na příkazové řádce

Do funkce main se v programovacím jazyku Rust nepředávají žádné parametry, takže pokud je zapotřebí přistupovat k argumentům příkazové řádky, je nutné použít odlišný přístup. Ten spočívá v použití iterátoru vráceného po zavolání env::args(). Tento iterátor obsahuje všechny předané parametry a na prvním místě i jméno souboru, který byl spuštěn:

use std::env;
 
fn main() {
    for arg in env::args() {
        println!("{}", arg);
    }
}

Předchozí příklad po svém spuštění (se zadáním tří parametrů) vypíše:

./239_env_all_args foo bar baz
 
./239_env_all_args
foo
bar
baz

V operačním systému Linux obsahuje první prvek iterátoru cestu ke spouštěnému souboru. Tu získáme velmi snadno, jen nesmíme zapomenout na to, že prvky vrácené iterátorem jsou typu Option, takže je nutné použít metodu .unwrap():

use std::env;
 
fn main() {
    let exename = env::args().nth(0);
    let arguments = env::args().count();
 
    println!("exename:   {}", exename.unwrap());
    println!("arguments: {}", arguments);
}

Předchozí příklad po svém spuštění (se zadáním tří parametrů) vypíše:

./240_env_exe_name foo bar baz
 
exename:   ./240_env_exe_name
arguments: 4

15. Repositář s demonstračními příklady

Všechny dnes popisované demonstrační příklady byly, podobně jako ve všech předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář:

Příklad Odkaz
221_format_basic.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/221_format_basic.rs
222_format_alternate_forms.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/222_format_alternate_for­ms.rs
223_format_width_align1.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/223_format_width_align1­.rs
224_format_width_align2.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/224_format_width_align2­.rs
225_format_fill.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/225_format_fill.rs
226_format_sign.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/226_format_sign.rs
227_format_padding.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/227_format_padding.rs
228_format_precision.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/228_format_precision.rs
229_format_width_param.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/229_format_width_param.rs
230_format_width_precision_params.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/230_format_width_precisi­on_params.rs
231_integers.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/231_integers.rs
232_integer_swaps.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/232_integer_swaps.rs
233_integer_rot_shift.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/233_integer_rot_shift.rs
234_floats.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/234_floats.rs
235_doubles.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/235_doubles.rs
236_env_macro.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/236_env_macro.rs
237_env_runtime.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/237_env_runtime.rs
238_env_all_vars.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/238_env_all_vars.rs
239_env_all_args.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/239_env_all_args.rs
240_env_exe_name.rs https://github.com/tisnik/pre­sentations/blob/master/rus­t/240_env_exe_name.rs

16. Odkazy na Internetu

  1. Module std::fmt
    https://doc.rust-lang.org/std/fmt/
  2. Macro std::println
    https://doc.rust-lang.org/std/macro.println.html
  3. Enum std::result::Result
    https://doc.rust-lang.org/std/result/enum.Result.html
  4. Module std::result
    https://doc.rust-lang.org/std/result/
  5. Result
    http://rustbyexample.com/std/re­sult.html
  6. Rust stdlib: Option
    https://doc.rust-lang.org/std/option/enum.Option.html
  7. Module std::option
    https://doc.rust-lang.org/std/option/index.html
  8. Rust by example: option
    http://rustbyexample.com/std/op­tion.html
  9. Rust by example: if-let
    http://rustbyexample.com/flow_con­trol/if_let.html
  10. Rust by example: while let
    http://rustbyexample.com/flow_con­trol/while_let.html
  11. Rust by example: Option<i32>
    http://rustbyexample.com/std/op­tion.html
  12. An Overview of Macros in Rust
    http://words.steveklabnik.com/an-overview-of-macros-in-rust
  13. A Practical Intro to Macros in Rust 1.0
    https://danielkeep.github.io/practical-intro-to-macros.html
  14. The Rust Programming Language: macros
    https://doc.rust-lang.org/beta/book/macros.html
  15. Rust by example: 15 macro_rules!
    http://rustbyexample.com/macros.html
  16. Module std::vec
    https://doc.rust-lang.org/nightly/std/vec/index.html
  17. Primitive Type isize
    https://doc.rust-lang.org/nightly/std/primi­tive.isize.html
  18. Primitive Type usize
    https://doc.rust-lang.org/nightly/std/primi­tive.usize.html
  19. Primitive Type array
    https://doc.rust-lang.org/nightly/std/primi­tive.array.html
  20. Module std::slice
    https://doc.rust-lang.org/nightly/std/slice/
  21. Rust by Example: 2.3 Arrays and Slices
    http://rustbyexample.com/pri­mitives/array.html
  22. What is the difference between Slice and Array (stackoverflow)
    http://stackoverflow.com/qu­estions/30794235/what-is-the-difference-between-slice-and-array
  23. Learning Rust With Entirely Too Many Linked Lists
    http://cglab.ca/~abeinges/blah/too-many-lists/book/
  24. Testcase: linked list
    http://rustbyexample.com/cus­tom_types/enum/testcase_lin­ked_list.html
  25. Operators and Overloading
    https://doc.rust-lang.org/book/operators-and-overloading.html
  26. Module std::ops
    https://doc.rust-lang.org/std/ops/index.html
  27. Module std::cmp
    https://doc.rust-lang.org/std/cmp/index.html
  28. Trait std::ops::Add
    https://doc.rust-lang.org/stable/std/ops/trait.Add.html
  29. Trait std::ops::AddAssign
    https://doc.rust-lang.org/std/ops/trait.AddAssign.html
  30. Trait std::ops::Drop
    https://doc.rust-lang.org/std/ops/trait.Drop.html
  31. Trait std::cmp::Eq
    https://doc.rust-lang.org/std/cmp/trait.Eq.html
  32. Struct std::boxed::Box
    https://doc.rust-lang.org/std/boxed/struct.Box.html
  33. Explore the ownership system in Rust
    https://nercury.github.io/rus­t/guide/2015/01/19/ownership­.html
  34. Rust's ownership and move semantic
    http://www.slideshare.net/sa­neyuki/rusts-ownership-and-move-semantics
  35. Trait std::marker::Copy
    https://doc.rust-lang.org/stable/std/marker/tra­it.Copy.html
  36. Trait std::clone::Clone
    https://doc.rust-lang.org/stable/std/clone/tra­it.Clone.html
  37. The Stack and the Heap
    https://doc.rust-lang.org/book/the-stack-and-the-heap.html
  38. Rust Compare: Pointers & References
    http://www.rust-compare.com/site/pointers.html
  39. Rust Compare: Parameters
    http://www.rust-compare.com/site/params.html
  40. Why does this compile? Automatic dereferencing?
    https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183
  41. Understanding Pointers, Ownership, and Lifetimes in Rust
    http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html
  42. Rust lang series episode #25 — pointers (#rust-series)
    https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series
  43. Rust – home page
    https://www.rust-lang.org/en-US/
  44. Rust – Frequently Asked Questions
    https://www.rust-lang.org/en-US/faq.html
  45. Destructuring and Pattern Matching
    https://pzol.github.io/get­ting_rusty/posts/20140417_des­tructuring_in_rust/
  46. The Rust Programming Language
    https://doc.rust-lang.org/book/
  47. Rust (programming language)
    https://en.wikipedia.org/wi­ki/Rust_%28programming_lan­guage%29
  48. Go – home page
    https://golang.org/
  49. Stack Overflow – Most Loved, Dreaded, and Wanted language
    https://stackoverflow.com/re­search/developer-survey-2016#technology-most-loved-dreaded-and-wanted
  50. Rust vs Go (dva roky staré hodnocení, od té doby došlo k posunům v obou jazycích)
    http://jaredforsyth.com/2014/03/22/rust-vs-go/
  51. Rust vs Go: My experience
    https://www.reddit.com/r/go­lang/comments/21m6jq/rust_vs_go_my_ex­perience/
  52. Friends of Rust (Organizations running Rust in production)
    https://www.rust-lang.org/en-US/friends.html
  53. Rust programs versus C++ g++
    https://benchmarksgame.ali­oth.debian.org/u64q/compa­re.php?lang=rust&lang2=gpp
  54. Další benchmarky (nejedná se o reálné příklady „ze života“)
    https://github.com/kostya/benchmarks
  55. Go na Redditu
    https://www.reddit.com/r/golang/
  56. Rust vs. Go
    http://vschart.com/compare/rust/vs/go-language
  57. Abstraction without overhead: traits in Rust
    https://blog.rust-lang.org/2015/05/11/traits.html
  58. Method Syntax
    https://doc.rust-lang.org/book/method-syntax.html
  59. Traits in Rust
    https://doc.rust-lang.org/book/traits.html
  60. Functional Programming in Rust – Part 1 : Function Abstraction
    http://blog.madhukaraphatak­.com/functional-programming-in-rust-part-1/
  61. Of the emerging systems languages Rust, D, Go and Nim, which is the strongest language and why?
    https://www.quora.com/Of-the-emerging-systems-languages-Rust-D-Go-and-Nim-which-is-the-strongest-language-and-why
  62. Chytré ukazatele (moderní verze jazyka C++) [MSDN]
    https://msdn.microsoft.com/cs-cz/library/hh279674.aspx
  63. UTF-8 Everywhere
    http://utf8everywhere.org/
  64. Rust by Example
    http://rustbyexample.com/
  65. Rust oficiálně ve Fedoře
    https://mojefedora.cz/rust-oficialne-ve-fedore/
  66. Resource acquisition is initialization
    https://en.wikipedia.org/wi­ki/Resource_acquisition_is_i­nitialization
  67. TIOBE index (October 2016)
    http://www.tiobe.com/tiobe-index/
  68. Porovnání Go, D a Rustu na OpenHubu:
    https://www.openhub.net/lan­guages/compare?language_na­me[]=-1&language_name[]=-1&language_name[]=dmd&lan­guage_name[]=golang&langu­age_name[]=rust&language_na­me[]=-1&measure=commits
  69. String Types in Rust
    http://www.suspectsemantic­s.com/blog/2016/03/27/str­ing-types-in-rust/
  70. Trait (computer programming)
    https://en.wikipedia.org/wi­ki/Trait_%28computer_program­ming%29
  71. Type inference
    https://en.wikipedia.org/wi­ki/Type_inference
Našli jste v článku chybu?
10. 3. 2017 15:13
Miloslav Ponkrác (neregistrovaný)

A polovina toho, co píšete, má problém i ve floatech. Protože float má pouhé 3 speciální typy hodnot (spíše rozsahy): NaN a dvě nekonečna.

Pokud nebudete číst příznaky od FPU, které detekuje různé výjimky, tak leccos nepoznáte. V tom je to stejné jako u int.

Například poznáte, proč je výsledek float operace NaN? To může být stejně jako 0/0, nebo ln(-2), nebo sqrt(-2), nebo nekonečně dalších možností.

Pokusy přidat příznaky a další informace do float hodnot, což typicky odneslo NaN, protože to…

9. 3. 2017 7:21

Tak nějak mě matou f64::INFINITY, f64::NEG_INFINITY, f64::NAN, předpokládal bych, že se to bude řešit přes Option.