• úvod
  • témata
  • události
  • tržiště
  • diskuze
  • nástěnka
  • přihlásit
    registrace
    ztracené heslo?
    SPIRALIRust - Programovací jazyk
    SPIKE411
    SPIKE411 --- ---
    Rust's Unsafe Pointer Types Need An Overhaul - Faultlore
    https://gankra.github.io/blah/fix-rust-pointers/
    SPIKE411
    SPIKE411 --- ---
    Writing Rust the Elixir way - 18 months later | Lunatic
    https://lunatic.solutions/blog/writing-rust-the-elixir-way-1.5-years-later/
    BONEFLUTE
    BONEFLUTE --- ---
    Ahoj. Rád bych do svého projektu zakomponoval scriptovací jazyk na řešení handlerů a rutin. V repozitářích je několik zajímavých projektů. Konkrétně mě zaujali: https://crates.io/crates/gluon a https://crates.io/crates/dyon
    Máte s tím nějaké praktické zkušenosti? Nebo i s jinými?
    BONEFLUTE
    BONEFLUTE --- ---
    SPIRALI: Moc děkuji za vysvětlení.
    SPIRALI
    SPIRALI --- ---
    BONEFLUTE: Cilem hry je ziskat:
    (1) Uvoleneni zdroju kdyz uz je nikdo nevyuziva
    (2) Zabranit tomu aby nekdo ziskal zaroven read and write referenci nebo dve write.

    Rc resi (1) tim ze ma counter ktery pocita kolik je uzivatelu te reference, kdyz spadne na 0 tak uvolnuje. "get_mut" na Rc pak ve specialnim pripade kdy counter ma hodnotu prave 1 umoznuje vratit &mut referenci, protoze tim ze vime ze jsme jedini kdo ma tuto referenci, tak je to bezpecne i vzhledem k (2). Pokud uz ale Root ma alespon dva Itemy tak Rc counter bude alespon na 2 a tedy get_mut selze (i kdyz nikdo zrovna nema read/write pristup). Proto je tam nutne dat RefCell, ktery slouzi k reseni (2) a zavede dalsi counter, ktery pocita rozpujcovane reference.

    Zkracene: Rc pocita kolik existuje mist na kterych o nas vedi, RefCell pocita kolik mist cte, pripadne jestli do nas nekdo zrovna nezapisuje.
    Oboji idealne hlida prekladac v dobe prekladu, ale nekdy to nejde vyjadrit a je treba tyto kontrolu shodit pomoci Rc/RefCellu do runtimu.
    BONEFLUTE
    BONEFLUTE --- ---
    SPIRALI: Ou! Paráda. A já se s tím tady mořím.
    Díky moc!

    Mohl by jsi mi prosím vysvětlit princip, proč to s get_mut() nefungovalo, a filozofii toho RefCell? Abych to pochopil, co za tím je.
    SPIRALI
    SPIRALI --- ---
    BONEFLUTE: Ah zapomel jsem jeste dodat ze to musis obalit RefCellem, Rc::get_mut ti nebude realne fungovat kdyz se refcounter zvedne.

    Tady je refcell reseni:
    Rust Playground
    https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=30ba12c987875ee3cb76f7b490473098
    BONEFLUTE
    BONEFLUTE --- ---
    Aha :-(

    fn append_to_root(root: &mut Rc<Root>, name: String) {
        Rc::get_mut(root).unwrap().items.push(Item {
    		name: name,
    	});
    }
    BONEFLUTE
    BONEFLUTE --- ---
    SPIRALI:
    Tak jasně. To by snad mělo být: Root::new() -> Rc[Self]. Ale dobře. Chápu tedy, že mi to nebude automaticky předávat jako self: Rc[Root]. OK.

    Podařilo se mi to zjednodušit. Toto funguje:
    struct Item {
        name: String
    }
    
    
    struct Root {
        name: String,
        items: Vec<Item>,
    }
    fn append_to_root(root: &mut Root, name: String) {
        root.items.push(Item { name: name });
    }
    
    
    fn main() {
        let mut root = Root {name: "/".to_string(), items: vec![] };
        append_to_root(&mut root, "Alef".to_string());
    
        println!("C: {}", root.name);
        println!("D: {}", root.items.len());
    }

    Když začnu předávat Rc, a pokud to chápu dobře, tak musím předávat Rc:
    use std::rc::Rc;
    
    
    struct Item {
        name: String
    }
    
    
    struct Root {
        name: String,
        items: Vec<Item>,
    }
    fn append_to_root(root: &mut Rc<Root>, name: String) {
        root.items.push(Item { name: name });
    }
    
    
    fn main() {
        let mut root = Rc::new(Root {name: "/".to_string(), items: vec![] });
        append_to_root(&mut root, "Alef".to_string());
    
        println!("C: {}", root.name);
        println!("D: {}", root.items.len());
    }
    tak to odmítne s:
    error[E0596]: cannot borrow data in an `Rc` as mutable
      --> src/main.rs:14:5
       |
    14 |     root.items.push(Item { name: name });
       |     ^^^^^^^^^^ cannot borrow as mutable

    Omlouvám se, vůbec se nechytám :-(
    SPIRALI
    SPIRALI --- ---
    BONEFLUTE: Ten root musi zit v Rc (Rc::new(Root:new(..)) a append nemuze brat jen self ale musi vzit cele to Rc.
    BONEFLUTE
    BONEFLUTE --- ---
    JUNIOR:
    error[E0308]: mismatched types
      --> src/main.rs:31:29
       |
    31 |         self.items.push(Item::new(&self, itemname));
       |                                   ^^^^^ expected struct `Rc`, found `&mut Root`
       |
       = note: expected reference `&Rc<Root>`
                  found reference `&&mut Root`
    JUNIOR
    JUNIOR --- ---
    BONEFLUTE: A když spustíš cargo tak ti to vyhodí co za error ? Ten debug v Rustu je naprosto skvělá věc
    BONEFLUTE
    BONEFLUTE --- ---
    JON: Tak já už nevím.

    Zkoušel jsem už všechno co mě napadlo. Ale vždycky jsem se na něčem zasekl. Já prostě nedokážu protlačit ten parent v metodě append.
    Tak jak to mám níže mi to nefunguje, protože jako `append(&mut self,` mi to vrací `Root`, místo `Rc[Root]`.
    Zkoušel jsem i nevracet Rc[Self] ale přímo Self. Ale tam jsem opět zasekl v append. Divoce jsem to vydereferencoval (`*(&*self)`) až do fáze, že to chtělo Copy trait. Což nechci.

    Můžete se mi prosím podívat na následující "ideální" kód, a poradit mi, jak to upravit?

    use std::rc::Rc;
    use std::fmt::Display;
    
    
    struct Item {
    	name: String,
    	parent: Rc<Root>,
    }
    impl Item {
    	pub fn new(parent: &Rc<Root>, name: String) -> Rc<Self> {
    		Rc::new(Self {
    			name: name,
    			parent: parent.clone(),
    		})
    	}
    }
    
    
    struct Root {
    	name: String,
    	items: Vec<Rc<Item>>,
    }
    impl Root {
    	pub fn new(name: String) -> Rc<Self> {
    		Rc::new(Self {
    			name: name,
    			items: vec![],
    		})
    	}
    	pub fn append(&mut self, itemname: String) {
    		self.items.push(Item::new(&self, itemname));
    	}
    }
    impl Display for Root {
        fn fmt(&self, w: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
            write!(w, "{} [", self.name)?;
            for x in self.items.iter() {
                write!(w, "{}, ", x.name)?;
    		}
            write!(w, "]")
        }
    }
    
    
    fn main() {
    	let tree = Root::new("Kay".to_string());
    	tree.append("Alfa".to_string());
    	tree.append("Beth".to_string());
    	println!("{}", tree);
    }
    BONEFLUTE
    BONEFLUTE --- ---
    JON: Supr. To by mohlo být ono. Díky moc.
    JON
    JON --- ---
    BONEFLUTE: hledej doubly linked list, neni to v rustu uplne jednoduche.

    Simple doubly-linked list in safe Rust · GitHub
    https://gist.github.com/matey-jack/3e19b6370c6f7036a9119b79a82098ca

    LinkedList in std::collections - Rust
    https://doc.rust-lang.org/std/collections/struct.LinkedList.html
    BONEFLUTE
    BONEFLUTE --- ---
    CUCHULAIN:
    Pardon. Dovysvětlím:
    Chci vytvořit strom komponent. App je kořen. Má kolekci Window. A každý Window má odkaz na svého rodiče. Tudíž předpokládám, že mu nemohu předat jen ten odkaz na App, protože bych tomu předal vlastnictví, a ony všechny ty okna odkazují na stejného rodiče. Nebo uvažuju špatně?
    Potřebuju, aby každý Window se dostal ke svému rodiči (bude mu totiž posílat zprávu).
    CUCHULAIN
    CUCHULAIN --- ---
    BONEFLUTE: takhle na první pohled mě napadá, že Window, ale nevím, co od toho očekáváš.
    BONEFLUTE
    BONEFLUTE --- ---
    Zdravím. Prosím o radu.

    Dělám strukturu asi takto:
    struct App {
        windows: Vec<Window>,
    }
    struct Window {
        parent: App,
        items: Vec<Control>,
    }
    struct Control {
        parent: ...
    }

    A teď uvažuju, jakého typu má být ten parent. Box[App]? Nebo Rc[App]?

    Zkoušel jsem to tak nějak různé, a vždycky z toho vylezla divná obluda. Prolejzal jsem zdrojáky knihoven, že se inspiruju, ale ty jsou na mě zase nad moje znalosti. Trochu se v tom topím.

    Předem díky.
    JUNIOR
    JUNIOR --- ---
    SHINING_KATE: Díky za perfektní odpověď. Přesně podobnou zkušenost jsem hledal, hlavně přesně s tím Actix a jak si dělá věci po svém. Nakonec po zralé úvaze to zkusím s Axum. Díky moc!
    SHINING_KATE
    SHINING_KATE --- ---
    JUNIOR: Ale disclaimer, to co děláme je docela komplexní aplikace, třeba jedna z našich servis musí zpracovávat jak HTTP Api, tak požadavky které přichází přes MLLP protokol, máme built-in request queue abychom zaručili odeslání requestů dalším službám (https://gitlab.com/famedly/company/backend/libraries/requeuest) a tak. Pro normální Api server bude Actix fajn, a má opravdu dobrou dokumentaci. Jen bych opravdu začala vývoj už na betě 4.0 a počítala s nějakým refaktoringem, protože mezi různými beta verzemi se dost měnilo api.

    A vyhla bych se Dieselu na databáze. Je v tom částečně osobní antipatie k ORM, ale diesel navíc pořád není async, má naprosto šílené chybové hlášky s šílenými typy a obecně mi spíš házel klacky pod nohy. Super je sqlx :)
    Kliknutím sem můžete změnit nastavení reklam