{"id":9558,"date":"2025-06-08T21:28:03","date_gmt":"2025-06-08T20:28:03","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=9558"},"modified":"2025-12-30T12:25:37","modified_gmt":"2025-12-30T11:25:37","slug":"rust-mutable-iterator-example","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/rust-mutable-iterator-example\/","title":{"rendered":"Rust Mutable Iterator example"},"content":{"rendered":"\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">pub trait Explainable {\n    fn do_explain(&amp;self)-> String;\n}\n\npub trait HasAccount {\n    fn get_account(&amp;self)-> String;\n    fn change_account(&amp;mut self, new_value: &amp;str);\n}\n\npub struct Person {\n    name: String,\n    account: String\n}\n\nimpl Explainable for Person {\n    fn do_explain(&amp;self)-> String {\n        return self.name.clone() + \" \" + self.account.as_str()\n    }\n}\n\nimpl HasAccount for Person {\n    fn change_account(&amp;mut self, new_value: &amp;str) {\n        self.account = new_value.to_string();\n    }\n    \n    fn get_account(&amp;self)-> String {\n        return self.account.clone();\n    }\n}\n\nfn change_accounts&lt;'a>(persons: impl Iterator&lt;Item = &amp;'a mut Person>) {\n    for p in persons {\n        println!(\"Changing person: {}\", p.name);\n        let mut new_str= String::with_capacity(100);\n        new_str.push_str(&amp;p.account);\n        new_str.push_str(\"_020\");\n        p.change_account(&amp;new_str);\n    }\n}\n\nfn change_accounts2&lt;'a>(persons: impl Iterator&lt;Item = &amp;'a mut dyn HasAccount>) {\n    for p in persons {\n        let mut new_str = String::with_capacity(100);\n        new_str.push_str(&amp;p.get_account());\n        new_str.push_str(\"_020\");\n        p.change_account(&amp;new_str);\n    }\n}\n\nfn change_accounts3&lt;'a, I>(persons: I)\nwhere\n    I: IntoIterator&lt;Item = &amp;'a mut dyn HasAccount>,\n{\n    for p in persons {\n        let mut new_str = String::with_capacity(100);\n        new_str.push_str(&amp;p.get_account());\n        new_str.push_str(\"_020\");\n        p.change_account(&amp;new_str);\n    }\n}\n\nfn change_accounts4&lt;'a, I>(persons: I)\nwhere\n    I: IntoIterator&lt;Item = &amp;'a mut Box&lt;dyn HasAccount>>,\n{\n    for p in persons {\n        let mut new_str = String::with_capacity(100);\n        new_str.push_str(&amp;p.get_account());\n        new_str.push_str(\"_020\");\n        p.change_account(&amp;new_str);\n    }\n}\n\n\/\/ Trait with both traits\ntrait Entity: Explainable + HasAccount {}\nimpl&lt;T: Explainable + HasAccount> Entity for T {}\n\n\nfn explain_all&lt;'a>(items: impl IntoIterator&lt;Item = &amp;'a Box&lt;dyn Entity>>) {\n    for item in items {\n        println!(\"{}\", item.do_explain());\n    }\n}\n\nfn change_all&lt;'a>(items: impl IntoIterator&lt;Item = &amp;'a mut Box&lt;dyn Entity>>) {\n    for item in items {\n        let mut new_str = item.get_account();\n        new_str.push_str(\"_mod\");\n        item.change_account(&amp;new_str);\n    }\n}\n\n\nfn get_boxed_entities1() -> Vec&lt;Box&lt;dyn Entity>> {\n    vec![\n        Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n        Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n    ]\n}\n\n\/\/ return an iterator\nfn get_boxed_entities2() -> impl Iterator&lt;Item = Box&lt;dyn Entity>> {\n    return vec![\n        Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n        Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n    ]\n    .into_iter()\n    .map(|p| p as Box&lt;dyn Entity>)\n}\n\n\n\nfn main() {\n    println!(\"Hello, world!\");\n\n    let mut persons = vec![\n        Person { name: \"Jan\".into(), account: \"2345234\".into() },\n        Person { name: \"Kees\".into(), account: \"342523\".into() }\n    ];\n\n    for p in persons.iter() { \/\/ &lt;- using .iter() here to allow multiple loops\n        let s = p.do_explain();\n        println!(\"{}\", s);\n    }\n\n    for p in persons.iter_mut() {\n        let new_str= p.account.clone() + \"_010\";\n        p.change_account(&amp;new_str);\n    }\n\n    change_accounts(persons.iter_mut());\n    change_accounts(persons.iter_mut());\n\n    change_accounts2(persons.iter_mut().map(|p| p as &amp;mut dyn HasAccount));\n\n    change_accounts3(persons.iter_mut().map(|p| p as &amp;mut dyn HasAccount));\n\n\n    for p in persons.iter() {\n        let s = p.do_explain();\n        println!(\"{}\", s);\n    }\n\n    \/\/ step 2\n    \n    let mut boxed: Vec&lt;Box&lt;dyn HasAccount>> = vec![\n        Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n        Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n    ];\n\n    change_accounts4(boxed.iter_mut()); \/\/boxed.iter_mut().map(|p| p.as_mut())\n\n    \/\/ step 3\n\n    let mut list: Vec&lt;Box&lt;dyn Entity>> = vec![\n        Box::new(Person { name: \"Jan\".into(), account: \"123\".into() }),\n        Box::new(Person { name: \"Kees\".into(), account: \"456\".into() }),\n    ];\n\n    \/\/ read\n    explain_all(list.iter()); \/\/.map(|x| x.as_ref())\n\n    \/\/ write\n    let iter = list.iter_mut(); \/\/.map(|x| x.as_mut())\n    change_all(iter);\n\n    \/\/ read again\n    explain_all(list.iter()); \/\/.map(|x| x.as_ref())\n\n\n    let mut list2 = get_boxed_entities1();\n    explain_all(list2.iter()); \n    let iter = list2.iter_mut();\n    change_all(iter);\n    explain_all(list2.iter());\n\n\n    let mut list3: Vec&lt;Box&lt;dyn Entity>> = get_boxed_entities2().collect();\n    explain_all(list3.iter()); \n    change_all(list3.iter_mut());\n    explain_all(list3.iter());\n\n    println!(\"Finished\");\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">trait IntoBoxedA&lt;'a>: IntoIterator&lt;Item = &amp;'a Box&lt;dyn A>> {}\nimpl&lt;'a, T> IntoBoxedA&lt;'a> for T where T: IntoIterator&lt;Item = &amp;'a Box&lt;dyn A>> {}\n\n\n\/\/ 3 variants with the same behaviour:\n\nfn process1&lt;'a, T: IntoBoxedA&lt;'a>>(items: T) {\n    ...\n}\n\nfn process1&lt;'a, T>(items: T)\nwhere\n    T: IntoBoxedA&lt;'a>\n{\n    ...\n}\n\nfn process1&lt;'a>(items: impl IntoBoxedA&lt;'a>) {\n    ...\n}\n\n\n\n\ud83d\udc49 Kies impl Trait voor korte functies, en de T: Trait-vorm als je meerdere trait bounds of het concrete generieke type nodig hebt.\n<\/pre>\n\n\n\n<p>Per trait a concrete alias<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">trait IntoBoxedA&lt;'a>: IntoIterator&lt;Item = &amp;'a Box&lt;dyn A>> {}\nimpl&lt;'a, T> IntoBoxedA&lt;'a> for T where T: IntoIterator&lt;Item = &amp;'a Box&lt;dyn A>> {}\n\ntrait IntoBoxedB&lt;'a>: IntoIterator&lt;Item = &amp;'a Box&lt;dyn B>> {}\nimpl&lt;'a, T> IntoBoxedB&lt;'a> for T where T: IntoIterator&lt;Item = &amp;'a Box&lt;dyn B>> {}\n\ntrait IntoBoxedC&lt;'a>: IntoIterator&lt;Item = &amp;'a Box&lt;dyn C>> {}\nimpl&lt;'a, T> IntoBoxedC&lt;'a> for T where T: IntoIterator&lt;Item = &amp;'a Box&lt;dyn C>> {}\n\n\nfn process1&lt;'a, T: IntoBoxedA&lt;'a>>(items: T) {\n    ...\n}\n\nfn process2&lt;'a, T: IntoBoxedB&lt;'a>>(items: T) {\n    ...\n}\n\n\nmacro_rules! define_into_boxed {\n    ($name:ident, $trait:path) => {\n        pub trait $name&lt;'a>: IntoIterator&lt;Item = &amp;'a Box&lt;dyn $trait>> {}\n        impl&lt;'a, T> $name&lt;'a> for T\n        where\n            T: IntoIterator&lt;Item = &amp;'a Box&lt;dyn $trait>>,\n        {}\n    };\n}\n\ntrait A {\n    fn do_a(&amp;self);\n}\n\ntrait B {\n    fn do_b(&amp;self);\n}\n\ntrait C {\n    fn do_c(&amp;self);\n}\n\ndefine_into_boxed!(IntoBoxedA, A);\ndefine_into_boxed!(IntoBoxedB, B);\ndefine_into_boxed!(IntoBoxedC, C);\n\nfn process1&lt;'a>(items: impl IntoBoxedA&lt;'a>) {\n    for a in items {\n        a.do_a();\n    }\n}\n\nfn process2&lt;'a>(items: impl IntoBoxedB&lt;'a>) {\n    for b in items {\n        b.do_b();\n    }\n}\n\n\n<\/pre>\n\n\n\n<p>Limetime errors<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ error[E0597]: `boxed` does not live long enough\n\/\/ error[E0759]: `boxed` captured by a closure, but it is dropped before the closure is called\n\n\nlet mut boxed: Vec&lt;Box&lt;dyn HasAccount>> = vec![\n    Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n    Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n];\n\nedit_accounts(boxed.iter_mut().map(|p| p.as_mut()));\n\n\/\/ solution: collect into a Vec, this causes the iterator to be used\n\nlet mut boxed: Vec&lt;Box&lt;dyn HasAccount>> = vec![\n    Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n    Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n];\n\nlet mapped: Vec&lt;_> = boxed.iter_mut().map(|p| p.as_mut()).collect();\nedit_accounts(mapped);\n\n\/\/ link original variable lifetime to iterator:\nfn make_iter&lt;'a>(\n    boxed: &amp;'a mut [Box&lt;dyn HasAccount>]\n) -> impl Iterator&lt;Item = &amp;'a mut dyn HasAccount> {\n    boxed.iter_mut().map(|b| b.as_mut())\n}\n\n\n\/\/ Full example:\n\ntrait HasAccount {\n    fn set_account(&amp;mut self, account: &amp;str);\n}\n\nstruct Person {\n    name: String,\n    account: String,\n}\n\nimpl HasAccount for Person {\n    fn set_account(&amp;mut self, account: &amp;str) {\n        self.account = account.to_string();\n    }\n}\n\nfn make_iter&lt;'a>(\n    boxed: &amp;'a mut [Box&lt;dyn HasAccount>]\n) -> impl Iterator&lt;Item = &amp;'a mut dyn HasAccount> {\n    boxed.iter_mut().map(|b| b.as_mut())\n}\n\nfn edit_accounts&lt;'a, I>(accounts: I)\nwhere\n    I: Iterator&lt;Item = &amp;'a mut dyn HasAccount>,\n{\n    for a in accounts {\n        a.set_account(\"updated\");\n    }\n}\n\nfn main() {\n    let mut boxed: Vec&lt;Box&lt;dyn HasAccount>> = vec![\n        Box::new(Person { name: \"Piet\".into(), account: \"abc\".into() }),\n        Box::new(Person { name: \"Klaas\".into(), account: \"xyz\".into() }),\n    ];\n\n    let iter = make_iter(&amp;mut boxed);\n    edit_accounts(iter);\n}\n\n\n\n\n<\/pre>\n\n\n\n<p>Service returning array\/vec<\/p>\n\n\n\n<p>Goede vraag \u2014 dit raakt precies de <strong>ownership-filosofie van Rust<\/strong> \ud83d\udc4d<br>Het korte antwoord is: <strong>nee, je hoeft meestal g\u00e9\u00e9n lijst mee te geven om te vullen<\/strong>.<br>De <em>meest idiomatische<\/em> manier is dat je functie <strong>zelf de data maakt en deze teruggeeft<\/strong>, zodat de caller automatisch owner wordt.<\/p>\n\n\n\n<p>Hieronder zet ik de patronen op een rij, van <em>meest aanbevolen<\/em> \u2192 <em>meer uitzonderlijk<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 1. <strong>Functie retourneert een <code>Vec&lt;T&gt;<\/code> (aanbevolen)<\/strong><\/h2>\n\n\n\n<p>Dit is veruit het meest gebruikte en duidelijke patroon.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct Item {\n    id: i32,\n    name: String,\n}\n\nfn load_items() -> Vec&lt;Item> {\n    let mut items = Vec::new();\n\n    items.push(Item { id: 1, name: \"A\".into() });\n    items.push(Item { id: 2, name: \"B\".into() });\n\n    items\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() {\n    let items = load_items(); \/\/ main is owner\n    println!(\"{}\", items.len());\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Waarom dit goed is<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ownership is <strong>glashelder<\/strong><\/li>\n\n\n\n<li>Geen lifetimes nodig<\/li>\n\n\n\n<li>Compiler kan optimaliseren (NRVO \/ move elision)<\/li>\n\n\n\n<li>Sluit perfect aan bij Rust-idiomen<\/li>\n<\/ul>\n\n\n\n<p>\ud83d\udc49 <strong>In 90% van de gevallen is dit wat je wilt<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 2. Result + ownership (bij fouten \/ IO \/ services)<\/h2>\n\n\n\n<p>Voor services is dit vaak n\u00f3g realistischer:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn load_items() -> Result&lt;Vec&lt;Item>, Box&lt;dyn std::error::Error>> {\n    Ok(vec![\n        Item { id: 1, name: \"A\".into() },\n        Item { id: 2, name: \"B\".into() },\n    ])\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let items = load_items()?; \/\/ caller is owner\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u26a0\ufe0f 3. Caller geeft een <code>&amp;mut Vec&lt;T&gt;<\/code> mee (meestal niet nodig)<\/h2>\n\n\n\n<p>Dit <em>kan<\/em>, maar is alleen zinvol als je <strong>expliciet wilt toevoegen aan bestaande data<\/strong>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn load_items_into(items: &amp;mut Vec&lt;Item>) {\n    items.push(Item { id: 1, name: \"A\".into() });\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let mut items = Vec::new();\nload_items_into(&amp;mut items);\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Nadelen<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Minder duidelijk ownership<\/li>\n\n\n\n<li>Minder ergonomisch<\/li>\n\n\n\n<li>Sneller borrow-complexiteit<\/li>\n<\/ul>\n\n\n\n<p>\ud83d\udc49 Gebruik dit alleen als:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>je wilt <em>append\u2019en<\/em><\/li>\n\n\n\n<li>performancekritisch bent<\/li>\n\n\n\n<li>of API-compatibiliteit nodig hebt<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 4. Iterator teruggeven (lazy \/ streaming)<\/h2>\n\n\n\n<p>Als je service <em>potentieel veel data<\/em> heeft of lazy wil zijn:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn load_items() -> impl Iterator&lt;Item = Item> {\n    vec![\n        Item { id: 1, name: \"A\".into() },\n        Item { id: 2, name: \"B\".into() },\n    ].into_iter()\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let items: Vec&lt;Item> = load_items().collect();\n<\/pre>\n\n\n\n<p>Caller is alsnog owner.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 5. Service-struct met methode (typisch voor \u201cservices\u201d)<\/h2>\n\n\n\n<p>In jouw \u201cservice\u201d-context waarschijnlijk het mooist:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct ItemService;\n\nimpl ItemService {\n    fn get_items(&amp;self) -> Vec&lt;Item> {\n        vec![\n            Item { id: 1, name: \"A\".into() },\n            Item { id: 2, name: \"B\".into() },\n        ]\n    }\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let service = ItemService;\nlet items = service.get_items(); \/\/ ownership hier\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u274c Wat je meestal <strong>niet<\/strong> wilt<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn get_items&lt;'a>() -> &amp;'a Vec&lt;Item> { ... }\n<\/pre>\n\n\n\n<p>\u274c Probleem:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wie is owner?<\/li>\n\n\n\n<li>Lifetime hell<\/li>\n\n\n\n<li>Vaak onmogelijk zonder <code>static<\/code> of interne opslag<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udded Beslisboom<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Situatie<\/th><th>Beste keuze<\/th><\/tr><\/thead><tbody><tr><td>Caller moet owner zijn<\/td><td><code>fn -&gt; Vec&lt;T&gt;<\/code><\/td><\/tr><tr><td>Kan falen<\/td><td><code>fn -&gt; Result&lt;Vec&lt;T&gt;, E&gt;<\/code><\/td><\/tr><tr><td>Grote\/lazy data<\/td><td><code>fn -&gt; impl Iterator&lt;Item = T&gt;<\/code><\/td><\/tr><tr><td>Append aan bestaande data<\/td><td><code>fn(&amp;mut Vec&lt;T&gt;)<\/code><\/td><\/tr><tr><td>Service-achtig<\/td><td><code>impl Service { fn -&gt; Vec&lt;T&gt; }<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfaf Samenvatting<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Rust wil dat ownership expliciet is \u2014 en retourneren is de schoonste vorm daarvan.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p>\u2714\ufe0f <strong>Laat je functie gewoon een <code>Vec&lt;T&gt;<\/code> teruggeven<\/strong><br>\u274c Niet vullen via parameters tenzij je daar echt een reden voor hebt<\/p>\n\n\n\n<p>Als je wilt, kan ik dit ook laten zien met:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>async services<\/li>\n\n\n\n<li>database calls<\/li>\n\n\n\n<li>trait-based services<\/li>\n\n\n\n<li><code>Arc&lt;Vec&lt;T>><\/code> \/ shared ownership<\/li>\n<\/ul>\n\n\n\n<p>Zeg maar \ud83d\udc4d<\/p>\n\n\n\n<p>Zeker \ud83d\udc4d Hieronder laat ik <strong>drie veelgebruikte manieren<\/strong> zien om deze functie aan te roepen, m\u00e9t nette error handling. Ik bouw het voorbeeld stap voor stap op.<\/p>\n\n\n\n<p>Voor de volledigheid eerst een minimale <code>Item<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#[derive(Debug)]\nstruct Item {\n    id: i32,\n    name: String,\n}\n<\/pre>\n\n\n\n<p>En jouw functie:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn load_items() -> Result&lt;Vec&lt;Item>, Box&lt;dyn std::error::Error>> {\n    Ok(vec![\n        Item { id: 1, name: \"A\".into() },\n        Item { id: 2, name: \"B\".into() },\n    ])\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 1. <strong>Idiomatic: <code>?<\/code> gebruiken (meest aanbevolen)<\/strong><\/h2>\n\n\n\n<p>Dit is wat je in bijna alle Rust-services en binaries ziet.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() -> Result&lt;(), Box&lt;dyn std::error::Error>> {\n    let items = load_items()?; \/\/ fout? \u2192 automatisch terug uit main\n\n    for item in items {\n        println!(\"{:?}\", item);\n    }\n\n    Ok(())\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Wat gebeurt hier?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>load_items()<\/code> geeft <code>Result&lt;Vec&lt;Item>, E><\/code><\/li>\n\n\n\n<li><code>?<\/code>:\n<ul class=\"wp-block-list\">\n<li>bij <code>Ok<\/code> \u2192 unwrapt de <code>Vec&lt;Item><\/code><\/li>\n\n\n\n<li>bij <code>Err<\/code> \u2192 returned direct uit <code>main<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>main<\/code> <strong>mag<\/strong> <code>Result<\/code> teruggeven \u2192 Rust print automatisch de fout<\/li>\n<\/ul>\n\n\n\n<p>\u2714\ufe0f <strong>Simpel, leesbaar, idiomatisch<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 2. <strong>Expliciet matchen (als je zelf wilt reageren)<\/strong><\/h2>\n\n\n\n<p>Handig als je logging of alternatieve flow wilt.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() {\n    match load_items() {\n        Ok(items) => {\n            println!(\"Items geladen:\");\n            for item in items {\n                println!(\"{:?}\", item);\n            }\n        }\n        Err(err) => {\n            eprintln!(\"\u274c Fout bij laden van items: {}\", err);\n        }\n    }\n}\n<\/pre>\n\n\n\n<p>\u2714\ufe0f Volledige controle<br>\u274c Meer boilerplate<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 3. <strong><code>if let Err<\/code> + early return<\/strong><\/h2>\n\n\n\n<p>Fijn als je snel wilt stoppen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() {\n    let items = match load_items() {\n        Ok(items) => items,\n        Err(e) => {\n            eprintln!(\"\u274c Kan items niet laden: {}\", e);\n            return;\n        }\n    };\n\n    println!(\"{} items geladen\", items.len());\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddea 4. Met eigen fouttype (iets geavanceerder)<\/h2>\n\n\n\n<p>Als je service groter wordt, is dit vaak beter dan <code>Box&lt;dyn Error&gt;<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">use std::fmt;\n\n#[derive(Debug)]\nenum LoadError {\n    DatabaseDown,\n}\n\nimpl fmt::Display for LoadError {\n    fn fmt(&amp;self, f: &amp;mut fmt::Formatter&lt;'_>) -> fmt::Result {\n        write!(f, \"Database is niet bereikbaar\")\n    }\n}\n\nimpl std::error::Error for LoadError {}\n\nfn load_items() -> Result&lt;Vec&lt;Item>, LoadError> {\n    Err(LoadError::DatabaseDown)\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() -> Result&lt;(), LoadError> {\n    let items = load_items()?;\n    println!(\"{:?}\", items);\n    Ok(())\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 Samenvatting<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Situatie<\/th><th>Aanpak<\/th><\/tr><\/thead><tbody><tr><td>CLI \/ service<\/td><td><code>main() -&gt; Result&lt;()&gt;<\/code> + <code>?<\/code><\/td><\/tr><tr><td>UI \/ API<\/td><td><code>match<\/code> of <code>map_err<\/code><\/td><\/tr><tr><td>Library code<\/td><td>Eigen error type<\/td><\/tr><tr><td>Snel stoppen<\/td><td><code>match<\/code> + <code>return<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>\ud83d\udc49 <strong>Aanrader voor jouw voorbeeld<\/strong>:<br>Gebruik variant <strong>#1 (<code>?<\/code> in <code>main<\/code>)<\/strong> \u2014 schoon en Rust-idiomatisch.<\/p>\n\n\n\n<p>Als je wilt, kan ik dit ook laten zien in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>async context (<code>tokio<\/code>)<\/li>\n\n\n\n<li>Web API handler<\/li>\n\n\n\n<li>unit tests (<code>assert!(load_items().is_ok())<\/code>)<\/li>\n\n\n\n<li>service trait met meerdere implementaties<\/li>\n<\/ul>\n\n\n\n<p>Mooi voorbeeld \ud83d\udc4d Dit leent zich <em>perfect<\/em> om te laten zien hoe je in Rust <strong>iteratoren<\/strong> maakt die hetzelfde doen als JS <code>function*<\/code>.<\/p>\n\n\n\n<p>Rust heeft geen generators zoals JS, maar je bereikt hetzelfde met:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>structs + <code>Iterator<\/code> trait<\/li>\n\n\n\n<li>of iterator-adapters (<code>map<\/code>, <code>flat_map<\/code>)<\/li>\n\n\n\n<li>zero-copy waar mogelijk (<code>&amp;str<\/code> slices)<\/li>\n<\/ul>\n\n\n\n<p>Ik laat hieronder een <strong>bewust eenvoudige CSV-parser<\/strong> zien, vergelijkbaar met jouw JS-code (dus geen volledige RFC4180).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfaf Doel (1-op-1 met jouw JS)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>String \u2192 <strong>regels iterator<\/strong><\/li>\n\n\n\n<li>Regel \u2192 <strong>CSV-waarden iterator<\/strong><\/li>\n\n\n\n<li>Waarden \u2192 decode \/ trim<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1\ufe0f\u20e3 Iterator: regels uit een string<\/h1>\n\n\n\n<p>In Rust is dit verrassend simpel: <code>lines()<\/code> <strong>is al een iterator<\/strong>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn get_lines_from_string(source: &amp;str) -> impl Iterator&lt;Item = &amp;str> {\n    source.lines()\n}\n<\/pre>\n\n\n\n<p>Gebruik:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">for line in get_lines_from_string(csv) {\n    println!(\"line: {}\", line);\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2\ufe0f\u20e3 Iterator: CSV-waarden uit \u00e9\u00e9n regel<\/h1>\n\n\n\n<p>Hier maken we <strong>zelf een iterator<\/strong> (vergelijkbaar met <code>function*<\/code>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">CSV-iterator struct<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct CsvValues&lt;'a> {\n    line: &amp;'a str,\n    separator: char,\n    pos: usize,\n    in_string: bool,\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Constructor<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn get_csv_values_from_line&lt;'a>(\n    line: &amp;'a str,\n    separator: char,\n) -> CsvValues&lt;'a> {\n    CsvValues {\n        line,\n        separator,\n        pos: 0,\n        in_string: false,\n    }\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Iterator-implementatie<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">impl&lt;'a> Iterator for CsvValues&lt;'a> {\n    type Item = &amp;'a str;\n\n    fn next(&amp;mut self) -> Option&lt;Self::Item> {\n        let bytes = self.line.as_bytes();\n        let start = self.pos;\n\n        while self.pos &lt; bytes.len() {\n            let c = bytes[self.pos] as char;\n\n            if c == '\"' {\n                self.in_string = !self.in_string;\n            } else if !self.in_string &amp;&amp; c == self.separator {\n                let value = &amp;self.line[start..self.pos];\n                self.pos += 1; \/\/ separator overslaan\n                return Some(value);\n            }\n\n            self.pos += 1;\n        }\n\n        if start &lt; self.line.len() {\n            return Some(&amp;self.line[start..]);\n        }\n\n        None\n    }\n}\n<\/pre>\n\n\n\n<p>\u2714\ufe0f Dit werkt <strong>lazy<\/strong><br>\u2714\ufe0f Geen allocaties<br>\u2714\ufe0f Net als JS <code>yield<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3\ufe0f\u20e3 Waarde decoderen (zoals JS <code>decodeValue<\/code>)<\/h1>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn decode_value(value: &amp;str) -> String {\n    value\n        .trim()\n        .trim_matches('\"')\n        .replace(\"\\\"\\\"\", \"\\\"\")\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4\ufe0f\u20e3 Alles samen (zoals jouw JS <code>for..of<\/code>)<\/h1>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn main() {\n    let csv = r#\"value1,\"value,with,comma\",\"value \"\"with quotes\"\" inside\",value4\"#;\n\n    for line in get_lines_from_string(csv) {\n        println!(\"======================\");\n\n        for raw in get_csv_values_from_line(line, ',') {\n            let value = decode_value(raw);\n            println!(\"value: {}\", value);\n        }\n    }\n}\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udda8\ufe0f Output<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">======================\nvalue: value1\nvalue: value,with,comma\nvalue: value \"with quotes\" inside\nvalue: value4\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 Vergelijking JS vs Rust<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>JS<\/th><th>Rust<\/th><\/tr><\/thead><tbody><tr><td><code>function*<\/code><\/td><td><code>struct + impl Iterator<\/code><\/td><\/tr><tr><td><code>yield<\/code><\/td><td><code>Some(value)<\/code> in <code>next()<\/code><\/td><\/tr><tr><td>Lazy<\/td><td>Lazy<\/td><\/tr><tr><td>String copies<\/td><td>Zero-copy (<code>&amp;str<\/code>)<\/td><\/tr><tr><td>Runtime checks<\/td><td>Compile-time safety<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Bonus: iterator chaining (erg Rust-achtig)<\/h2>\n\n\n\n<p>Je kunt dit ook <em>combineren<\/em>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let values: Vec&lt;String> =\n    get_lines_from_string(csv)\n        .flat_map(|l| get_csv_values_from_line(l, ','))\n        .map(decode_value)\n        .collect();\n<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udccc Wanneer dit patroon gebruiken?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>streaming parsing<\/li>\n\n\n\n<li>grote bestanden<\/li>\n\n\n\n<li>zero-copy verwerking<\/li>\n\n\n\n<li>pipeline-achtige logica (net als JS generators)<\/li>\n<\/ul>\n\n\n\n<p>Als je wilt, kan ik ook:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>async iterators laten zien<\/li>\n\n\n\n<li>een <code>CsvParser<\/code> service maken<\/li>\n\n\n\n<li>of laten zien hoe dit eruit ziet met <code>BufRead<\/code> (file streaming)<\/li>\n<\/ul>\n\n\n\n<p>Zeg maar \ud83d\udc4d<\/p>\n\n\n\n<p>Ja \u2014 <strong>dit is precies het punt waar veel mensen uit JS\/Python tegenaan lopen in Rust<\/strong> \ud83d\ude42<br>Het korte, eerlijke antwoord is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u274c <strong>Rust heeft geen <code>yield return<\/code>-syntax zoals JS of C#<\/strong><br>\u2705 Maar je kunt <strong>bijna hetzelfde ergonomische resultaat<\/strong> krijgen met een paar idiomatische patronen.<\/p>\n<\/blockquote>\n\n\n\n<p>Ik laat ze oplopend zien, beginnend bij <em>wat het dichtst bij <code>yield<\/code> komt<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Optie 1: <code>std::iter::from_fn<\/code> (het dichtst bij <code>yield return<\/code>)<\/h2>\n\n\n\n<p>Dit is <strong>conceptueel bijna 1-op-1 <code>yield<\/code><\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Definitie zoals jij vroeg<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn get_csv_values_from_line&lt;'a>(\n    line: &amp;'a str,\n    separator: char,\n) -> impl Iterator&lt;Item = &amp;'a str> {\n    let mut pos = 0usize;\n    let mut in_string = false;\n\n    std::iter::from_fn(move || {\n        let bytes = line.as_bytes();\n        let start = pos;\n\n        while pos &lt; bytes.len() {\n            let c = bytes[pos] as char;\n\n            if c == '\"' {\n                in_string = !in_string;\n            } else if !in_string &amp;&amp; c == separator {\n                let value = &amp;line[start..pos];\n                pos += 1;\n                return Some(value); \/\/ \u2b05\ufe0f yield\n            }\n\n            pos += 1;\n        }\n\n        if start &lt; line.len() {\n            pos = line.len();\n            return Some(&amp;line[start..]); \/\/ \u2b05\ufe0f final yield\n        }\n\n        None\n    })\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Gebruik<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">for v in get_csv_values_from_line(line, ',') {\n    println!(\"value: {}\", v);\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Waarom dit zo goed is<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Geen extra struct nodig<\/li>\n\n\n\n<li>Geen <code>impl Iterator for ...<\/code><\/li>\n\n\n\n<li>State zit netjes in de closure<\/li>\n\n\n\n<li><strong><code>Some(...)<\/code> \u2248 <code>yield<\/code><\/strong><\/li>\n<\/ul>\n\n\n\n<p>\ud83d\udc49 <strong>Dit is meestal wat je zoekt als je \u201cyield return\u201d denkt<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe1 Optie 2: Custom <code>struct + impl Iterator<\/code> (meest expliciet)<\/h2>\n\n\n\n<p>Dit had je al gezien \u2014 dit is <strong>meer boilerplate<\/strong>, maar wel het fundament.<\/p>\n\n\n\n<p>Gebruik dit als:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>je iterator herbruikbaar is<\/li>\n\n\n\n<li>je state wilt exposen<\/li>\n\n\n\n<li>je performance-maximalisme wilt<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udfe1 Optie 3: <code>Vec<\/code> bouwen en <code>into_iter()<\/code> (geen echte yield)<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fn get_csv_values_from_line&lt;'a>(\n    line: &amp;'a str,\n    separator: char,\n) -> impl Iterator&lt;Item = &amp;'a str> {\n    let mut values = Vec::new();\n    let mut start = 0;\n    let mut in_string = false;\n\n    for (i, c) in line.char_indices() {\n        if c == '\"' {\n            in_string = !in_string;\n        } else if !in_string &amp;&amp; c == separator {\n            values.push(&amp;line[start..i]);\n            start = i + 1;\n        }\n    }\n\n    values.push(&amp;line[start..]);\n    values.into_iter()\n}\n<\/pre>\n\n\n\n<p>\u274c Niet lazy<br>\u274c Extra allocaties<br>\u2714\ufe0f Simpel<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Optie 4: Nightly Rust (<code>#![feature(generators)]<\/code>) \u274c<\/h2>\n\n\n\n<p>Er <strong>bestaan<\/strong> generators in nightly Rust, maar:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>niet stabiel<\/li>\n\n\n\n<li>syntax is anders<\/li>\n\n\n\n<li><strong>niet aanbevolen voor productie<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 Vergelijking met C#\/JS<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Concept<\/th><th>JS \/ C#<\/th><th>Rust<\/th><\/tr><\/thead><tbody><tr><td><code>yield<\/code><\/td><td><code>yield value<\/code><\/td><td><code>Some(value)<\/code><\/td><\/tr><tr><td>Generator state<\/td><td>impliciet<\/td><td>closure \/ struct<\/td><\/tr><tr><td>Lazy<\/td><td>ja<\/td><td>ja<\/td><\/tr><tr><td>Syntax sugar<\/td><td>ja<\/td><td>nee (bewust)<\/td><\/tr><tr><td>Zero-cost<\/td><td>\u274c<\/td><td>\u2705<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfaf Conclusie (belangrijk)<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Als je in Rust denkt:<br><strong>\u201cIk wil gewoon een yield-return-achtig ding\u201d<\/strong><br>\ud83d\udc49 <strong>gebruik <code>std::iter::from_fn<\/code><\/strong><\/p>\n<\/blockquote>\n\n\n\n<p>Het is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>compact<\/li>\n\n\n\n<li>leesbaar<\/li>\n\n\n\n<li>idiomatisch<\/li>\n\n\n\n<li>exact jouw gevraagde signature<\/li>\n<\/ul>\n\n\n\n<p>Als je wilt, kan ik:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>async <code>yield<\/code>-achtige voorbeelden geven<\/li>\n\n\n\n<li>laten zien hoe dit eruitziet bij file streaming<\/li>\n\n\n\n<li>of dit ombouwen naar een echte CSV-service<\/li>\n<\/ul>\n\n\n\n<p>Zeg maar \ud83d\udc4d<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Per trait a concrete alias Limetime errors Service returning array\/vec Goede vraag \u2014 dit raakt precies de ownership-filosofie van Rust \ud83d\udc4dHet korte antwoord is: nee, je hoeft meestal g\u00e9\u00e9n lijst mee te geven om te vullen.De meest idiomatische manier is dat je functie zelf de data maakt en deze teruggeeft, zodat de caller automatisch owner [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9558","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9558","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=9558"}],"version-history":[{"count":14,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9558\/revisions"}],"predecessor-version":[{"id":10016,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/9558\/revisions\/10016"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=9558"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=9558"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=9558"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}