[{"data":1,"prerenderedAt":6587},["ShallowReactive",2],{"/de-de/blog/learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions":3,"navigation-de-de":5804,"banner-de-de":6236,"footer-de-de":6244,"blog-post-authors-de-de-Michael Friedrich":6484,"blog-related-posts-de-de-learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions":6499,"blog-promotions-de-de":6524,"next-steps-de-de":6577},{"id":4,"title":5,"authors":6,"body":8,"category":5780,"date":5781,"description":5782,"extension":5783,"externalUrl":5784,"faq":5784,"featured":5785,"heroImage":5786,"meta":5787,"navigation":445,"path":5788,"seo":5789,"slug":5793,"stem":5794,"tags":5795,"template":5801,"updatedDate":5802,"__hash__":5803},"blogPosts/de-de/blog/learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions.md","Lerne fortschrittliche Rust-Programmierung mit KI-Unterstützung",[7],"Michael Friedrich",{"type":9,"value":10,"toc":5743},"minimark",[11,27,35,213,218,231,235,249,256,289,299,306,309,330,333,350,353,368,375,378,381,392,416,495,501,513,516,534,581,584,607,610,753,759,774,781,784,798,822,828,835,935,940,943,965,971,977,983,989,992,1238,1279,1300,1306,1310,1323,1335,1342,1361,1412,1418,1473,1484,1519,1691,1697,1709,1712,1748,1797,1820,1829,1836,1842,1845,1848,1851,1872,1881,1895,1901,1904,1928,1975,1981,1990,1995,1998,2001,2028,2046,2057,2072,2078,2081,2370,2383,2414,2420,2424,2433,2442,2462,2668,2682,2709,2715,2718,2721,2915,2933,2943,2949,2952,2958,2961,2970,2980,2986,2993,3049,3052,3061,3075,3087,3120,3127,3358,3364,3404,3407,3411,3424,3448,3460,3597,3603,3619,3625,3771,3775,3778,3807,3813,4005,4008,4014,4017,4024,4152,4160,4418,4421,4441,4449,4461,4486,4569,4578,4810,4816,4820,4833,4923,4937,4940,5124,5136,5142,5148,5154,5157,5266,5269,5296,5301,5304,5308,5311,5328,5471,5609,5612,5615,5624,5639,5642,5656,5662,5668,5671,5678,5692,5695,5698,5718,5724,5727,5739],[12,13,14,15,21,22,26],"p",{},"Vor mehr als 20 Jahren musste ich für eine Programmiersprache die MSDN-Bibliothek von Visual Studio 6 mit 6 CD-ROMs installieren. Algorithmen mit Stift und Papier, Bücher für Entwurfsmuster und MSDN-Abfragen waren oft zeitaufwendig. Das Erlernen neuer Programmiersprachen hat sich mit Remote-Zusammenarbeit und KI stark gewandelt. Jetzt kannst du einen ",[16,17,20],"a",{"href":18,"rel":19},"https://about.gitlab.com/blog/quick-start-guide-for-gitlab-workspaces/",[],"Remote Development Workspace"," nutzen, deinen Bildschirm freigeben und zusammen programmieren. Mit ",[16,23,25],{"href":24},"/gitlab-duo-agent-platform/","GitLab Duo Codevorschläge"," hast du immer einen intelligenten Partner. Codevorschläge lernt von deinem Programmierstil und deiner Erfahrung. Es werden nur Input und Kontext benötigt.",[12,28,29,30,34],{},"Wir bauen auf den ",[16,31,33],{"href":32},"/blog/learning-rust-with-a-little-help-from-ai-code-suggestions-getting-started/","Blogbeitrag „Erste Schritte“"," auf und erstellen eine einfache Feed-Reader-Anwendung.",[36,37,38,53,79,93,107,121,127,153,173,193],"ul",{},[39,40,41,45],"li",{},[16,42,44],{"href":43},"#preparations","Vorbereitungen",[36,46,47],{},[39,48,49],{},[16,50,52],{"href":51},"#code-suggestions","Codevorschläge",[39,54,55,59],{},[16,56,58],{"href":57},"#continue-learning-rust","Rust vertiefen",[36,60,61,67,73],{},[39,62,63],{},[16,64,66],{"href":65},"#hello-reader-app","Hallo, Reader-App",[39,68,69],{},[16,70,72],{"href":71},"#initialize-project","Projekt initialisieren",[39,74,75],{},[16,76,78],{"href":77},"#define-rss-feed-urls","RSS-Feed-URLs definieren",[39,80,81,85],{},[16,82,84],{"href":83},"#modules","Module",[36,86,87],{},[39,88,89],{},[16,90,92],{"href":91},"#call-the-module-function-in-main","Modulfunktion im main() aufrufen",[39,94,95,99],{},[16,96,98],{"href":97},"#crates","Crates",[36,100,101],{},[39,102,103],{},[16,104,106],{"href":105},"#feed-rs-parse-xml-feed","feed-rs: XML-Feed parsen",[39,108,109,113],{},[16,110,112],{"href":111},"#runtime-configuration-program-arguments","Laufzeit-Konfiguration: Programmargumente",[36,114,115],{},[39,116,117],{},[16,118,120],{"href":119},"#user-input-error-handling","Umgang mit Benutzereingabefehlern",[39,122,123],{},[16,124,126],{"href":125},"#persistence-and-data-storage","Persistenz und Datenspeicherung",[39,128,129,133],{},[16,130,132],{"href":131},"#optimization","Optimierung",[36,134,135,141,147],{},[39,136,137],{},[16,138,140],{"href":139},"#asynchronous-execution","Asynchrone Ausführung",[39,142,143],{},[16,144,146],{"href":145},"#spawning-threads","Threads spawnen",[39,148,149],{},[16,150,152],{"href":151},"#function-scopes-threads-and-closures","Funktionsumfänge, Threads und Abschlüsse",[39,154,155,159],{},[16,156,158],{"href":157},"#parse-feed-xml-into-object-types","Feed-XML in Objekte parsen",[36,160,161,167],{},[39,162,163],{},[16,164,166],{"href":165},"#map-generic-feed-data-types","Generische Feed-Datentypen zuordnen",[39,168,169],{},[16,170,172],{"href":171},"#error-handling-with-option-unwrap","Fehlerbehebung mit Option::unwrap()",[39,174,175,179],{},[16,176,178],{"href":177},"#benchmarks","Benchmarks",[36,180,181,187],{},[39,182,183],{},[16,184,186],{"href":185},"#sequential-vs-parallel-execution-benchmark","Benchmarks für sequentielle/parallele Ausführung",[39,188,189],{},[16,190,192],{"href":191},"#cicd-with-rust-caching","CI/CD mit Rust-Caching",[39,194,195,199],{},[16,196,198],{"href":197},"#what-is-next","Wie geht es weiter?",[36,200,201,207],{},[39,202,203],{},[16,204,206],{"href":205},"#async-learning-exercises","Asynchrone Lernübungen",[39,208,209],{},[16,210,212],{"href":211},"#share-your-feedback","Teile dein Feedback",[214,215,217],"h2",{"id":216},"vorbereitung","Vorbereitung",[12,219,220,221,225,226,230],{},"Richte ",[16,222,224],{"href":223},"/blog/learning-rust-with-a-little-help-from-ai-code-suggestions-getting-started/#vs-code","VS Code"," und ",[16,227,229],{"href":228},"/blog/learning-rust-with-a-little-help-from-ai-code-suggestions-getting-started/#development-environment-for-rust","deine Entwicklungsumgebung mit Rust"," ein.",[232,233,52],"h3",{"id":234},"codevorschläge",[12,236,237,238,242,243,248],{},"Mache dich vorher damit vertraut. GitLab Duo Codevorschläge werden angezeigt, während du tippst. Drücke ",[239,240,241],"code",{},"tab",", um einen Codevorschlag anzunehmen. Das Schreiben von neuem Code funktioniert zuverlässiger als das Refactoring von bestehendem Code. Der gleiche Codevorschlag wird ggf. nicht erneut angezeigt, wenn du einen Codevorschlag löschst. Codevorschläge sind gerade in der Betaphase und wir verbessern die Genauigkeit der generierten Inhalte. Sieh dir die ",[16,244,247],{"href":245,"rel":246},"https://docs.gitlab.com/user/project/repository/code_suggestions/#known-limitations",[],"bekannten Einschränkungen"," an.",[12,250,251,255],{},[252,253,254],"strong",{},"Tipp:"," Die neueste Version von Codevorschläge unterstützt mehrzeilige Anweisungen. Passe die Spezifikationen an deine Bedürfnisse an, um bessere Vorschläge zu erhalten.",[257,258,263],"pre",{"className":259,"code":260,"language":261,"meta":262,"style":262},"language-rust shiki shiki-themes github-light","    // Create a function that iterates over the source array\n    // and fetches the data using HTTP from the RSS feed items. // Store the results in a new hash map.\n    // Print the hash map to the terminal.\n","rust","",[239,264,265,274,283],{"__ignoreMap":262},[266,267,270],"span",{"class":268,"line":269},"line",1,[266,271,273],{"class":272},"sAwPA","    // Create a function that iterates over the source array\n",[266,275,277,280],{"class":268,"line":276},2,[266,278,279],{"class":272},"    // and fetches the data using HTTP from the RSS feed items.",[266,281,282],{"class":272}," // Store the results in a new hash map.\n",[266,284,286],{"class":268,"line":285},3,[266,287,288],{"class":272},"    // Print the hash map to the terminal.\n",[12,290,291,292,294,295,298],{},"Die VS-Code-Erweiterung wird angezeigt, wenn ein Vorschlag angeboten wird. Mit ",[239,293,241],{}," kannst du die vorgeschlagene(n) Zeile(n) oder mit ",[239,296,297],{},"cmd cursor right"," ein Wort annehmen. Über das Menü mit den drei Punkten kannst du immer die Symbolleiste anzeigen.",[12,300,301],{},[302,303],"img",{"alt":304,"src":305},"VS Code überlagert GitLab Duo Codevorschläge mit Anweisungen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398627/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_code_suggestions_options_overlay_keep_toolbar.png",[214,307,58],{"id":308},"rust-vertiefen",[12,310,311,312,317,318,323,324,329],{},"Vertiefen wir nun Rust, eine der ",[16,313,316],{"href":314,"rel":315},"https://docs.gitlab.com/user/project/repository/code_suggestions/#supported-languages",[],"unterstützten Sprachen in Codevorschläge",". ",[16,319,322],{"href":320,"rel":321},"https://doc.rust-lang.org/rust-by-example/",[],"Rust by Example"," und das offizielle ",[16,325,328],{"href":326,"rel":327},"https://doc.rust-lang.org/book/",[],"Rust-Buch"," bieten einen guten Einstieg. Auf beide Ressourcen wird hier verwiesen.",[232,331,66],{"id":332},"hallo-reader-app",[12,334,335,336,338,339,344,345,349],{},"Es gibt viele Möglichkeiten, eine Anwendung zu erstellen und Rust zu lernen. Einige beinhalten die Nutzung bestehender Rust-Bibliotheken, der ",[239,337,98],{},". Wir verwenden sie weiter unten. Du kannst eine App mit einer Befehlszeile erstellen, die Bilder verarbeitet und die Ergebnisse in eine Datei schreibt. Es macht Spaß, ein Labyrinth zu lösen oder ein Sudoku-Lösungsprogramm zu schreiben. Spieleentwicklung ist auch gut. Das Buch ",[16,340,343],{"href":341,"rel":342},"https://hands-on-rust.com/",[],"Hands-on Rust"," bietet einen Lernpfad für ein Dungeon-Crawler-Spiel. Fatima Sarah Khalid hat ",[16,346,348],{"href":347},"/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions/","Dragon Realm in C++ mit ein wenig KI-Unterstützung"," gestartet.",[12,351,352],{},"Ein echter Anwendungsfall: Wichtige Infos sollen in einem RSS-Feed für (Sicherheits-)Releases, Blogbeiträge und Diskussionen in Foren wie Hacker News gesammelt werden. Oft möchten wir nach Keywords oder Versionen filtern. Mit diesen Anforderungen können wir eine Anforderungsliste erstellen:",[354,355,356,359,362,365],"ol",{},[39,357,358],{},"Daten von verschiedenen Quellen abrufen (HTTP-Websites, REST API, RSS-Feeds). RSS-Feeds in der ersten Iteration.",[39,360,361],{},"Die Daten parsen.",[39,363,364],{},"Die Daten den Benutzer(innen) präsentieren oder auf die Festplatte schreiben.",[39,366,367],{},"Die Leistung optimieren.",[12,369,370,371],{},"Diese Anwendungsausgabe ist nach den Lernschritten verfügbar:\n",[302,372],{"alt":373,"src":374},"VS-Code-Terminal, Cargo-Run mit formatierter Feedelement-Ausgabe","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398628/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_cargo_run_formatted_output_final.png",[12,376,377],{},"Die Anwendung sollte modular und die Grundlage für weitere Datentypen, Filter und Hooks sein, um später Aktionen auszulösen.",[232,379,72],{"id":380},"projekt-initialisieren",[12,382,383,384,387,388,391],{},"Zur Erinnerung: ",[239,385,386],{},"cargo init"," im Projekt-Root erstellt die Dateistruktur, darunter den Eingangspunkt ",[239,389,390],{},"main()",". Daher lernen wir nun, wie wir Rust-Module erstellen und verwenden.",[12,393,394,395,398,399,401,402,405,406,409,410,415],{},"Erstelle ein neues Verzeichnis ",[239,396,397],{},"learn-rust-ai-app-reader",", wechsle dorthin und führe ",[239,400,386],{}," aus. Dieser Befehl führt implizit ",[239,403,404],{},"git init"," aus, um ein neues Git-Repository lokal zu initialisieren. Zuletzt wird der Git-Remote-Repository-Pfad konfiguriert, z. B. ",[239,407,408],{},"https://gitlab.com/gitlab-da/use-cases/ai/learn-with-ai/learn-rust-ai-app-reader",". Passe den Pfad an. Durch das Pushen des Git-Repositorys ",[16,411,414],{"href":412,"rel":413},"https://docs.gitlab.com/user/project/#create-a-new-project-with-git-push",[],"wird automatisch ein neues privates Projekt in GitLab erstellt",".",[257,417,421],{"className":418,"code":419,"language":420,"meta":262,"style":262},"language-shell shiki shiki-themes github-light","mkdir learn-rust-ai-app-reader\ncd learn-rust-ai-app-reader\n\ncargo init\n\ngit remote add origin https://gitlab.com/gitlab-da/use-cases/ai/learn-with-ai/learn-rust-ai-app-reader.git\ngit push --set-upstream origin main\n","shell",[239,422,423,433,441,447,456,461,479],{"__ignoreMap":262},[266,424,425,429],{"class":268,"line":269},[266,426,428],{"class":427},"s7eDp","mkdir",[266,430,432],{"class":431},"sYBdl"," learn-rust-ai-app-reader\n",[266,434,435,439],{"class":268,"line":276},[266,436,438],{"class":437},"sYu0t","cd",[266,440,432],{"class":431},[266,442,443],{"class":268,"line":285},[266,444,446],{"emptyLinePlaceholder":445},true,"\n",[266,448,450,453],{"class":268,"line":449},4,[266,451,452],{"class":427},"cargo",[266,454,455],{"class":431}," init\n",[266,457,459],{"class":268,"line":458},5,[266,460,446],{"emptyLinePlaceholder":445},[266,462,464,467,470,473,476],{"class":268,"line":463},6,[266,465,466],{"class":427},"git",[266,468,469],{"class":431}," remote",[266,471,472],{"class":431}," add",[266,474,475],{"class":431}," origin",[266,477,478],{"class":431}," https://gitlab.com/gitlab-da/use-cases/ai/learn-with-ai/learn-rust-ai-app-reader.git\n",[266,480,482,484,487,490,492],{"class":268,"line":481},7,[266,483,466],{"class":427},[266,485,486],{"class":431}," push",[266,488,489],{"class":437}," --set-upstream",[266,491,475],{"class":431},[266,493,494],{"class":431}," main\n",[12,496,497,498,500],{},"Öffne VS Code aus dem neu erstellten Verzeichnis. Die CLI ",[239,499,239],{}," öffnet ein neues VS-Code-Fenster auf macOS.",[257,502,504],{"className":418,"code":503,"language":420,"meta":262,"style":262},"code .\n",[239,505,506],{"__ignoreMap":262},[266,507,508,510],{"class":268,"line":269},[266,509,239],{"class":427},[266,511,512],{"class":431}," .\n",[232,514,78],{"id":515},"rss-feed-urls-definieren",[12,517,518,519,522,523,525,526,533],{},"Füge eine neue Hashmap hinzu, um die RSS-Feed-URLs in der Datei ",[239,520,521],{},"src/main.rs"," in der Funktion ",[239,524,390],{}," zu speichern. Du kannst mit GitLab Duo Codevorschläge über einen mehrzeiligen Kommentar ein ",[16,527,530],{"href":528,"rel":529},"https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html",[],[239,531,532],{},"HashMap","-Objekt erstellen und mit Standardwerten für Hacker News und TechCrunch initialisieren. Hinweis: Stelle sicher, dass die URLs korrekt sind, wenn du Vorschläge erhältst.",[257,535,537],{"className":259,"code":536,"language":261,"meta":262,"style":262},"fn main() {\n    // Define RSS feed URLs in the variable rss_feeds\n    // Use a HashMap\n    // Add Hacker News and TechCrunch\n    // Ensure to use String as type\n\n}\n",[239,538,539,552,557,562,567,572,576],{"__ignoreMap":262},[266,540,541,545,548],{"class":268,"line":269},[266,542,544],{"class":543},"sD7c4","fn",[266,546,547],{"class":427}," main",[266,549,551],{"class":550},"sgsFI","() {\n",[266,553,554],{"class":268,"line":276},[266,555,556],{"class":272},"    // Define RSS feed URLs in the variable rss_feeds\n",[266,558,559],{"class":268,"line":285},[266,560,561],{"class":272},"    // Use a HashMap\n",[266,563,564],{"class":268,"line":449},[266,565,566],{"class":272},"    // Add Hacker News and TechCrunch\n",[266,568,569],{"class":268,"line":458},[266,570,571],{"class":272},"    // Ensure to use String as type\n",[266,573,574],{"class":268,"line":463},[266,575,446],{"emptyLinePlaceholder":445},[266,577,578],{"class":268,"line":481},[266,579,580],{"class":550},"}\n",[12,582,583],{},"Anweisungen sind enthalten für:\n:",[354,585,586,592,597,600],{},[39,587,588,589,415],{},"Den Variablennamen ",[239,590,591],{},"rss_feeds",[39,593,594,595,415],{},"Den Typ ",[239,596,532],{},[39,598,599],{},"Initiale Seed-Schlüssel-/Wertpaare.",[39,601,602,603,606],{},"Den String als Typ (sichtbar mit ",[239,604,605],{},"to_string()","-Aufrufen).",[12,608,609],{},"Ein möglicher vorgeschlagener Pfad:",[257,611,613],{"className":259,"code":612,"language":261,"meta":262,"style":262},"use std::collections::HashMap;\n\nfn main() {\n    // Define RSS feed URLs in the variable rss_feeds\n    // Use a HashMap\n    // Add Hacker News and TechCrunch\n    // Ensure to use String as type\n    let rss_feeds = HashMap::from([\n        (\"Hacker News\".to_string(), \"https://news.ycombinator.com/rss\".to_string()),\n        (\"TechCrunch\".to_string(), \"https://techcrunch.com/feed/\".to_string()),\n    ]);\n\n}\n",[239,614,615,636,640,648,652,656,660,664,687,714,737,743,748],{"__ignoreMap":262},[266,616,617,620,623,626,629,631,633],{"class":268,"line":269},[266,618,619],{"class":543},"use",[266,621,622],{"class":427}," std",[266,624,625],{"class":543},"::",[266,627,628],{"class":427},"collections",[266,630,625],{"class":543},[266,632,532],{"class":427},[266,634,635],{"class":550},";\n",[266,637,638],{"class":268,"line":276},[266,639,446],{"emptyLinePlaceholder":445},[266,641,642,644,646],{"class":268,"line":285},[266,643,544],{"class":543},[266,645,547],{"class":427},[266,647,551],{"class":550},[266,649,650],{"class":268,"line":449},[266,651,556],{"class":272},[266,653,654],{"class":268,"line":458},[266,655,561],{"class":272},[266,657,658],{"class":268,"line":463},[266,659,566],{"class":272},[266,661,662],{"class":268,"line":481},[266,663,571],{"class":272},[266,665,667,670,673,676,679,681,684],{"class":268,"line":666},8,[266,668,669],{"class":543},"    let",[266,671,672],{"class":550}," rss_feeds ",[266,674,675],{"class":543},"=",[266,677,678],{"class":427}," HashMap",[266,680,625],{"class":543},[266,682,683],{"class":427},"from",[266,685,686],{"class":550},"([\n",[266,688,690,693,696,698,701,704,707,709,711],{"class":268,"line":689},9,[266,691,692],{"class":550},"        (",[266,694,695],{"class":431},"\"Hacker News\"",[266,697,415],{"class":543},[266,699,700],{"class":427},"to_string",[266,702,703],{"class":550},"(), ",[266,705,706],{"class":431},"\"https://news.ycombinator.com/rss\"",[266,708,415],{"class":543},[266,710,700],{"class":427},[266,712,713],{"class":550},"()),\n",[266,715,717,719,722,724,726,728,731,733,735],{"class":268,"line":716},10,[266,718,692],{"class":550},[266,720,721],{"class":431},"\"TechCrunch\"",[266,723,415],{"class":543},[266,725,700],{"class":427},[266,727,703],{"class":550},[266,729,730],{"class":431},"\"https://techcrunch.com/feed/\"",[266,732,415],{"class":543},[266,734,700],{"class":427},[266,736,713],{"class":550},[266,738,740],{"class":268,"line":739},11,[266,741,742],{"class":550},"    ]);\n",[266,744,746],{"class":268,"line":745},12,[266,747,446],{"emptyLinePlaceholder":445},[266,749,751],{"class":268,"line":750},13,[266,752,580],{"class":550},[12,754,755],{},[302,756],{"alt":757,"src":758},"VS Code mit Codevorschlägen für RSS-Feed-URLs für Hacker News und TechCrunch","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398627/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_main_array_rss_feed_urls_suggested.png",[12,760,761,762,765,766,769,770,773],{},"Öffne ein neues Terminal in VS Code (cmd Umschalt p – suche nach ",[239,763,764],{},"terminal","). Führe ",[239,767,768],{},"cargo build"," aus, um die Änderungen zu erstellen. Die Fehlermeldung weist dich an, den Import von ",[239,771,772],{},"use std::collections::HashMap;"," hinzuzufügen.",[12,775,776,777,780],{},"Der nächste Schritt betrifft die RSS-Feed-URLs. ",[16,778,779],{"href":32},"Im letzten Blogbeitrag"," haben wir Code in Funktionen aufgeteilt. Wir möchten den Code für unsere Reader-Anwendung modular mit Rust-Modulen strukturieren.",[214,782,84],{"id":783},"module",[12,785,786,790,791,793,794,797],{},[16,787,84],{"href":788,"rel":789},"https://doc.rust-lang.org/rust-by-example/mod.html",[]," organisieren Code. Mit ihnen können auch Funktionen im Modulbereich ausgeblendet und der Zugriff darauf vom Bereich main() aus beschränkt werden. In unserer Reader-Anwendung möchten wir den RSS-Feed abrufen/XML-Antwort parsen. Der Caller ",[239,792,390],{}," sollte nur auf die Funktion ",[239,795,796],{},"get_feeds()"," zugreifen können, andere Funktionen sind nur im Modul verfügbar.",[12,799,800,801,804,805,808,809,812,813,815,816,821],{},"Erstelle eine neue Datei ",[239,802,803],{},"feed_reader.rs"," im Verzeichnis ",[239,806,807],{},"src/",". Weise Codevorschläge an, ein öffentliches Modul ",[239,810,811],{},"feed_reader"," und eine öffentliche Funktion ",[239,814,796],{}," mit einer String-HashMap als Eingabe zu erstellen. Wichtig: Die Datei- und Modulnamen müssen gemäß der ",[16,817,820],{"href":818,"rel":819},"https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html",[],"Rust-Modulstruktur"," identisch sein.",[12,823,824],{},[302,825],{"alt":826,"src":827},"Codevorschläge: öffentliches Modul mit Funktions- und Eingabetypen erstellen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398624/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_public_module_function_input.png",[12,829,830,831,834],{},"Wenn du Codevorschläge mit Namen/Typ der Eingabevariablen anweist, wird auch das Modul ",[239,832,833],{},"std::collections::HashMap"," importiert. Tipp: Experimentiere mit Kommentaren und verfeinere die Variablentypen. Die Übergabe von Funktionsparametern als Objektreferenzen gilt in Rust als Best Practice.",[257,836,838],{"className":259,"code":837,"language":261,"meta":262,"style":262},"// Create public module feed_reader\n// Define get_feeds() function which takes rss_feeds as String HashMap reference as input\npub mod feed_reader {\n    use std::collections::HashMap;\n\n    pub fn get_feeds(rss_feeds: &HashMap\u003CString, String>) {\n        // Do something with the RSS feeds\n    }\n}\n",[239,839,840,845,850,864,881,885,921,926,931],{"__ignoreMap":262},[266,841,842],{"class":268,"line":269},[266,843,844],{"class":272},"// Create public module feed_reader\n",[266,846,847],{"class":268,"line":276},[266,848,849],{"class":272},"// Define get_feeds() function which takes rss_feeds as String HashMap reference as input\n",[266,851,852,855,858,861],{"class":268,"line":285},[266,853,854],{"class":543},"pub",[266,856,857],{"class":543}," mod",[266,859,860],{"class":427}," feed_reader",[266,862,863],{"class":550}," {\n",[266,865,866,869,871,873,875,877,879],{"class":268,"line":449},[266,867,868],{"class":543},"    use",[266,870,622],{"class":427},[266,872,625],{"class":543},[266,874,628],{"class":427},[266,876,625],{"class":543},[266,878,532],{"class":427},[266,880,635],{"class":550},[266,882,883],{"class":268,"line":458},[266,884,446],{"emptyLinePlaceholder":445},[266,886,887,890,893,896,899,902,905,907,910,913,916,918],{"class":268,"line":463},[266,888,889],{"class":543},"    pub",[266,891,892],{"class":543}," fn",[266,894,895],{"class":427}," get_feeds",[266,897,898],{"class":550},"(rss_feeds",[266,900,901],{"class":543},":",[266,903,904],{"class":543}," &",[266,906,532],{"class":427},[266,908,909],{"class":550},"\u003C",[266,911,912],{"class":427},"String",[266,914,915],{"class":550},", ",[266,917,912],{"class":427},[266,919,920],{"class":550},">) {\n",[266,922,923],{"class":268,"line":481},[266,924,925],{"class":272},"        // Do something with the RSS feeds\n",[266,927,928],{"class":268,"line":666},[266,929,930],{"class":550},"    }\n",[266,932,933],{"class":268,"line":689},[266,934,580],{"class":550},[12,936,937],{},[302,938],{"alt":939,"src":827},"Codevorschläge: öffentliches Modul mit Funktion get_feeds() und vorgeschlagener Eingabevariable",[12,941,942],{},"Weise Codevorschläge innerhalb der Funktion weiter an:",[354,944,945,950,955,960],{},[39,946,947],{},[239,948,949],{},"// Iterate over the RSS feed URLs",[39,951,952],{},[239,953,954],{},"// Fetch URL content",[39,956,957],{},[239,958,959],{},"// Parse XML body",[39,961,962],{},[239,963,964],{},"// Print the result",[12,966,967],{},[302,968],{"alt":969,"src":970},"Codevorschläge: öffentliches Modul mit Funktion get_feeds(), Schritt 1: iterieren","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398622/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_module_function_01_iterate.png",[12,972,973],{},[302,974],{"alt":975,"src":976},"Codevorschläge: öffentliches Modul mit Funktion get_feeds(), Schritt 2: URL-Inhalt abrufen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398622/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_module_function_02_fetch_content.png",[12,978,979],{},[302,980],{"alt":981,"src":982},"Codevorschläge: öffentliches Modul mit Funktionget_feeds(), Schritt 3: XML-Body parsen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398622/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_module_function_03_parse_body.png",[12,984,985],{},[302,986],{"alt":987,"src":988},"Codevorschläge: öffentliches Modul mit Funktionget_feeds(), Schritt 4: Ergebnisse drucken","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398623/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_module_function_04_print_result.png",[12,990,991],{},"Codevorschlag:",[257,993,995],{"className":259,"code":994,"language":261,"meta":262,"style":262},"// Create public module feed_reader\n// Define get_feeds() function which takes rss_feeds as String HashMap reference as input\npub mod feed_reader {\n    use std::collections::HashMap;\n\n    pub fn get_feeds(rss_feeds: &HashMap\u003CString, String>) {\n        // Iterate over the RSS feed URLs\n        for (name, url) in rss_feeds {\n            println!(\"{}: {}\", name, url);\n\n            // Fetch URL content\n            let body = reqwest::blocking::get(url).unwrap().text().unwrap();\n\n            // Parse XML body\n            let parsed_body = roxmltree::Document::parse(&body).unwrap();\n\n            // Print the result\n            println!(\"{:#?}\", parsed_body);\n        }\n    }\n}\n",[239,996,997,1001,1005,1015,1031,1035,1061,1066,1080,1094,1098,1103,1151,1155,1161,1198,1203,1209,1222,1228,1233],{"__ignoreMap":262},[266,998,999],{"class":268,"line":269},[266,1000,844],{"class":272},[266,1002,1003],{"class":268,"line":276},[266,1004,849],{"class":272},[266,1006,1007,1009,1011,1013],{"class":268,"line":285},[266,1008,854],{"class":543},[266,1010,857],{"class":543},[266,1012,860],{"class":427},[266,1014,863],{"class":550},[266,1016,1017,1019,1021,1023,1025,1027,1029],{"class":268,"line":449},[266,1018,868],{"class":543},[266,1020,622],{"class":427},[266,1022,625],{"class":543},[266,1024,628],{"class":427},[266,1026,625],{"class":543},[266,1028,532],{"class":427},[266,1030,635],{"class":550},[266,1032,1033],{"class":268,"line":458},[266,1034,446],{"emptyLinePlaceholder":445},[266,1036,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057,1059],{"class":268,"line":463},[266,1038,889],{"class":543},[266,1040,892],{"class":543},[266,1042,895],{"class":427},[266,1044,898],{"class":550},[266,1046,901],{"class":543},[266,1048,904],{"class":543},[266,1050,532],{"class":427},[266,1052,909],{"class":550},[266,1054,912],{"class":427},[266,1056,915],{"class":550},[266,1058,912],{"class":427},[266,1060,920],{"class":550},[266,1062,1063],{"class":268,"line":481},[266,1064,1065],{"class":272},"        // Iterate over the RSS feed URLs\n",[266,1067,1068,1071,1074,1077],{"class":268,"line":666},[266,1069,1070],{"class":543},"        for",[266,1072,1073],{"class":550}," (name, url) ",[266,1075,1076],{"class":543},"in",[266,1078,1079],{"class":550}," rss_feeds {\n",[266,1081,1082,1085,1088,1091],{"class":268,"line":689},[266,1083,1084],{"class":427},"            println!",[266,1086,1087],{"class":550},"(",[266,1089,1090],{"class":431},"\"{}: {}\"",[266,1092,1093],{"class":550},", name, url);\n",[266,1095,1096],{"class":268,"line":716},[266,1097,446],{"emptyLinePlaceholder":445},[266,1099,1100],{"class":268,"line":739},[266,1101,1102],{"class":272},"            // Fetch URL content\n",[266,1104,1105,1108,1111,1113,1116,1118,1121,1123,1126,1129,1131,1134,1137,1139,1142,1144,1146,1148],{"class":268,"line":745},[266,1106,1107],{"class":543},"            let",[266,1109,1110],{"class":550}," body ",[266,1112,675],{"class":543},[266,1114,1115],{"class":427}," reqwest",[266,1117,625],{"class":543},[266,1119,1120],{"class":427},"blocking",[266,1122,625],{"class":543},[266,1124,1125],{"class":427},"get",[266,1127,1128],{"class":550},"(url)",[266,1130,415],{"class":543},[266,1132,1133],{"class":427},"unwrap",[266,1135,1136],{"class":550},"()",[266,1138,415],{"class":543},[266,1140,1141],{"class":427},"text",[266,1143,1136],{"class":550},[266,1145,415],{"class":543},[266,1147,1133],{"class":427},[266,1149,1150],{"class":550},"();\n",[266,1152,1153],{"class":268,"line":750},[266,1154,446],{"emptyLinePlaceholder":445},[266,1156,1158],{"class":268,"line":1157},14,[266,1159,1160],{"class":272},"            // Parse XML body\n",[266,1162,1164,1166,1169,1171,1174,1176,1179,1181,1184,1186,1189,1192,1194,1196],{"class":268,"line":1163},15,[266,1165,1107],{"class":543},[266,1167,1168],{"class":550}," parsed_body ",[266,1170,675],{"class":543},[266,1172,1173],{"class":427}," roxmltree",[266,1175,625],{"class":543},[266,1177,1178],{"class":427},"Document",[266,1180,625],{"class":543},[266,1182,1183],{"class":427},"parse",[266,1185,1087],{"class":550},[266,1187,1188],{"class":543},"&",[266,1190,1191],{"class":550},"body)",[266,1193,415],{"class":543},[266,1195,1133],{"class":427},[266,1197,1150],{"class":550},[266,1199,1201],{"class":268,"line":1200},16,[266,1202,446],{"emptyLinePlaceholder":445},[266,1204,1206],{"class":268,"line":1205},17,[266,1207,1208],{"class":272},"            // Print the result\n",[266,1210,1212,1214,1216,1219],{"class":268,"line":1211},18,[266,1213,1084],{"class":427},[266,1215,1087],{"class":550},[266,1217,1218],{"class":431},"\"{:#?}\"",[266,1220,1221],{"class":550},", parsed_body);\n",[266,1223,1225],{"class":268,"line":1224},19,[266,1226,1227],{"class":550},"        }\n",[266,1229,1231],{"class":268,"line":1230},20,[266,1232,930],{"class":550},[266,1234,1236],{"class":268,"line":1235},21,[266,1237,580],{"class":550},[12,1239,1240,1241,1248,1249,1252,1253,1261,1262,1265,1266,1268,1269,1271,1272,1274,1275,1278],{},"Du siehst ein neues Keyword: ",[16,1242,1245],{"href":1243,"rel":1244},"https://doc.rust-lang.org/rust-by-example/error/option_unwrap.html",[],[239,1246,1247],{},"unwrap()",". Rust unterstützt keine ",[239,1250,1251],{},"null","-Werte und verwendet immer den ",[16,1254,1257,1258],{"href":1255,"rel":1256},"https://doc.rust-lang.org/rust-by-example/std/option.html",[],"Typ ",[239,1259,1260],{},"Option",". Wenn du einen bestimmten wrapped-Typ verwenden willst, z. B. ",[239,1263,1264],{},"Text"," oder ",[239,1267,912],{},", rufe die Methode ",[239,1270,1247],{}," auf, um den Wert zu erhalten. Methode ",[239,1273,1247],{}," gerät bei Wert ",[239,1276,1277],{},"None"," in Panik.",[12,1280,1281,1284,1285,1288,1289,317,1291,1299],{},[252,1282,1283],{},"Hinweis"," Codevorschläge bezogen sich auf Funktion ",[239,1286,1287],{},"reqwest:: blocking::get"," für Kommentaranweisung ",[239,1290,954],{},[16,1292,1295,1296],{"href":1293,"rel":1294},"https://docs.rs/reqwest/latest/reqwest/",[],"Crate ",[239,1297,1298],{},"reqwest"," ist kein Tippfehler. Sie bietet einen praktischen, übergeordneten HTTP-Client für asynchrone und blockierende Anfragen.",[12,1301,1302,1303,1305],{},"Parsen des XML-Textes ist schwierig. Du erhältst ggf. unterschiedliche Ergebnisse, das Schema ist nicht für jede RSS-Feed-URL gleich. Rufen wir die Funktion ",[239,1304,796],{}," auf und verbessern den Code.",[232,1307,1309],{"id":1308},"modulfunktion-in-main-aufrufen","Modulfunktion in main() aufrufen",[12,1311,1312,1313,1315,1316,1265,1319,1322],{},"Funktion main() kennt Funktion ",[239,1314,796],{}," noch nicht, wir müssen ihr Modul importieren. Evtl. kennst du schon die Keywords ",[239,1317,1318],{},"include",[239,1320,1321],{},"import",". Das Rust-Modulsystem ist anders.",[12,1324,1325,1326,1328,1329,1331,1332,1334],{},"Module sind in Pfadverzeichnissen organisiert. Hier liegen beide Quelldateien auf derselben Verzeichnisebene vor. ",[239,1327,803],{}," wird als Crate interpretiert, die ein Modul ",[239,1330,811],{}," enthält, das Funktion ",[239,1333,796],{}," definiert.",[257,1336,1340],{"className":1337,"code":1339,"language":1141,"meta":262},[1338],"language-text","src/\n  main.rs\n  feed_reader.rs\n",[239,1341,1339],{"__ignoreMap":262},[12,1343,1344,1345,1347,1348,1350,1351,1356,1357,1360],{},"Um auf ",[239,1346,796],{}," aus Datei ",[239,1349,803],{}," zuzugreifen, müssen wir den ",[16,1352,1355],{"href":1353,"rel":1354},"https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html",[],"Modulpfad"," in den Bereich ",[239,1358,1359],{},"main.rs"," bringen, dann den vollständigen Funktionspfad aufrufen.",[257,1362,1364],{"className":259,"code":1363,"language":261,"meta":262,"style":262},"mod feed_reader;\n\nfn main() {\n\n    feed_reader::feed_reader::get_feeds(&rss_feeds);\n\n",[239,1365,1366,1375,1379,1387,1391],{"__ignoreMap":262},[266,1367,1368,1371,1373],{"class":268,"line":269},[266,1369,1370],{"class":543},"mod",[266,1372,860],{"class":427},[266,1374,635],{"class":550},[266,1376,1377],{"class":268,"line":276},[266,1378,446],{"emptyLinePlaceholder":445},[266,1380,1381,1383,1385],{"class":268,"line":285},[266,1382,544],{"class":543},[266,1384,547],{"class":427},[266,1386,551],{"class":550},[266,1388,1389],{"class":268,"line":449},[266,1390,446],{"emptyLinePlaceholder":445},[266,1392,1393,1396,1398,1400,1402,1405,1407,1409],{"class":268,"line":458},[266,1394,1395],{"class":427},"    feed_reader",[266,1397,625],{"class":543},[266,1399,811],{"class":427},[266,1401,625],{"class":543},[266,1403,1404],{"class":427},"get_feeds",[266,1406,1087],{"class":550},[266,1408,1188],{"class":543},[266,1410,1411],{"class":550},"rss_feeds);\n",[12,1413,1414,1415,1417],{},"Alternativ können wir den vollständigen Funktionspfad mit Keyword ",[239,1416,619],{}," importieren und später den kurzen Funktionsnamen verwenden.",[257,1419,1421],{"className":259,"code":1420,"language":261,"meta":262,"style":262},"mod feed_reader;\nuse feed_reader::feed_reader::get_feeds;\n\nfn main() {\n\n    get_feeds(&rss_feeds);\n\n",[239,1422,1423,1431,1446,1450,1458,1462],{"__ignoreMap":262},[266,1424,1425,1427,1429],{"class":268,"line":269},[266,1426,1370],{"class":543},[266,1428,860],{"class":427},[266,1430,635],{"class":550},[266,1432,1433,1435,1437,1439,1441,1443],{"class":268,"line":276},[266,1434,619],{"class":543},[266,1436,860],{"class":427},[266,1438,625],{"class":543},[266,1440,811],{"class":427},[266,1442,625],{"class":543},[266,1444,1445],{"class":550},"get_feeds;\n",[266,1447,1448],{"class":268,"line":285},[266,1449,446],{"emptyLinePlaceholder":445},[266,1451,1452,1454,1456],{"class":268,"line":449},[266,1453,544],{"class":543},[266,1455,547],{"class":427},[266,1457,551],{"class":550},[266,1459,1460],{"class":268,"line":458},[266,1461,446],{"emptyLinePlaceholder":445},[266,1463,1464,1467,1469,1471],{"class":268,"line":463},[266,1465,1466],{"class":427},"    get_feeds",[266,1468,1087],{"class":550},[266,1470,1188],{"class":543},[266,1472,1411],{"class":550},[12,1474,1475,1477,1478,1483],{},[252,1476,254],{}," Lies den Blogbeitrag ",[16,1479,1482],{"href":1480,"rel":1481},"https://www.sheshbabu.com/posts/rust-module-system/",[],"Erklärung des Rust-Modulsystems"," für ein besseres visuelles Verständnis.",[257,1485,1489],{"className":1486,"code":1487,"language":1488,"meta":262,"style":262},"language-diff shiki shiki-themes github-light","\nfn main() {\n    // ...\n\n    // Print feed_reader get_feeds() output\n    println!(\"{}\", feed_reader::get_feeds(&rss_feeds));\n","diff",[239,1490,1491,1495,1500,1505,1509,1514],{"__ignoreMap":262},[266,1492,1493],{"class":268,"line":269},[266,1494,446],{"emptyLinePlaceholder":445},[266,1496,1497],{"class":268,"line":276},[266,1498,1499],{"class":550},"fn main() {\n",[266,1501,1502],{"class":268,"line":285},[266,1503,1504],{"class":550},"    // ...\n",[266,1506,1507],{"class":268,"line":449},[266,1508,446],{"emptyLinePlaceholder":445},[266,1510,1511],{"class":268,"line":458},[266,1512,1513],{"class":550},"    // Print feed_reader get_feeds() output\n",[266,1515,1516],{"class":268,"line":463},[266,1517,1518],{"class":550},"    println!(\"{}\", feed_reader::get_feeds(&rss_feeds));\n",[257,1520,1522],{"className":259,"code":1521,"language":261,"meta":262,"style":262},"use std::collections::HashMap;\n\nmod feed_reader;\n// Alternative: Import full function path\n//use feed_reader::feed_reader::get_feeds;\n\nfn main() {\n    // Define RSS feed URLs in the variable rss_feeds\n    // Use a HashMap\n    // Add Hacker News and TechCrunch\n    // Ensure to use String as type\n    let rss_feeds = HashMap::from([\n        (\"Hacker News\".to_string(), \"https://news.ycombinator.com/rss\".to_string()),\n        (\"TechCrunch\".to_string(), \"https://techcrunch.com/feed/\".to_string()),\n    ]);\n\n    // Call get_feeds() from feed_reader module\n    feed_reader::feed_reader::get_feeds(&rss_feeds);\n    // Alternative: Imported full path, use short path here.\n    //get_feeds(&rss_feeds);\n}\n",[239,1523,1524,1540,1544,1552,1557,1562,1566,1574,1578,1582,1586,1590,1606,1626,1646,1650,1654,1659,1677,1682,1687],{"__ignoreMap":262},[266,1525,1526,1528,1530,1532,1534,1536,1538],{"class":268,"line":269},[266,1527,619],{"class":543},[266,1529,622],{"class":427},[266,1531,625],{"class":543},[266,1533,628],{"class":427},[266,1535,625],{"class":543},[266,1537,532],{"class":427},[266,1539,635],{"class":550},[266,1541,1542],{"class":268,"line":276},[266,1543,446],{"emptyLinePlaceholder":445},[266,1545,1546,1548,1550],{"class":268,"line":285},[266,1547,1370],{"class":543},[266,1549,860],{"class":427},[266,1551,635],{"class":550},[266,1553,1554],{"class":268,"line":449},[266,1555,1556],{"class":272},"// Alternative: Import full function path\n",[266,1558,1559],{"class":268,"line":458},[266,1560,1561],{"class":272},"//use feed_reader::feed_reader::get_feeds;\n",[266,1563,1564],{"class":268,"line":463},[266,1565,446],{"emptyLinePlaceholder":445},[266,1567,1568,1570,1572],{"class":268,"line":481},[266,1569,544],{"class":543},[266,1571,547],{"class":427},[266,1573,551],{"class":550},[266,1575,1576],{"class":268,"line":666},[266,1577,556],{"class":272},[266,1579,1580],{"class":268,"line":689},[266,1581,561],{"class":272},[266,1583,1584],{"class":268,"line":716},[266,1585,566],{"class":272},[266,1587,1588],{"class":268,"line":739},[266,1589,571],{"class":272},[266,1591,1592,1594,1596,1598,1600,1602,1604],{"class":268,"line":745},[266,1593,669],{"class":543},[266,1595,672],{"class":550},[266,1597,675],{"class":543},[266,1599,678],{"class":427},[266,1601,625],{"class":543},[266,1603,683],{"class":427},[266,1605,686],{"class":550},[266,1607,1608,1610,1612,1614,1616,1618,1620,1622,1624],{"class":268,"line":750},[266,1609,692],{"class":550},[266,1611,695],{"class":431},[266,1613,415],{"class":543},[266,1615,700],{"class":427},[266,1617,703],{"class":550},[266,1619,706],{"class":431},[266,1621,415],{"class":543},[266,1623,700],{"class":427},[266,1625,713],{"class":550},[266,1627,1628,1630,1632,1634,1636,1638,1640,1642,1644],{"class":268,"line":1157},[266,1629,692],{"class":550},[266,1631,721],{"class":431},[266,1633,415],{"class":543},[266,1635,700],{"class":427},[266,1637,703],{"class":550},[266,1639,730],{"class":431},[266,1641,415],{"class":543},[266,1643,700],{"class":427},[266,1645,713],{"class":550},[266,1647,1648],{"class":268,"line":1163},[266,1649,742],{"class":550},[266,1651,1652],{"class":268,"line":1200},[266,1653,446],{"emptyLinePlaceholder":445},[266,1655,1656],{"class":268,"line":1205},[266,1657,1658],{"class":272},"    // Call get_feeds() from feed_reader module\n",[266,1660,1661,1663,1665,1667,1669,1671,1673,1675],{"class":268,"line":1211},[266,1662,1395],{"class":427},[266,1664,625],{"class":543},[266,1666,811],{"class":427},[266,1668,625],{"class":543},[266,1670,1404],{"class":427},[266,1672,1087],{"class":550},[266,1674,1188],{"class":543},[266,1676,1411],{"class":550},[266,1678,1679],{"class":268,"line":1224},[266,1680,1681],{"class":272},"    // Alternative: Imported full path, use short path here.\n",[266,1683,1684],{"class":268,"line":1230},[266,1685,1686],{"class":272},"    //get_feeds(&rss_feeds);\n",[266,1688,1689],{"class":268,"line":1235},[266,1690,580],{"class":550},[12,1692,1693,1694,1696],{},"Führe ",[239,1695,768],{}," erneut im Terminal aus, um den Code zu erstellen.",[257,1698,1700],{"className":418,"code":1699,"language":420,"meta":262,"style":262},"cargo build\n",[239,1701,1702],{"__ignoreMap":262},[266,1703,1704,1706],{"class":268,"line":269},[266,1705,452],{"class":427},[266,1707,1708],{"class":431}," build\n",[12,1710,1711],{},"Potenzielle Build-Fehler, wenn sich Codevorschläge auf allgemeinen Code und Bibliotheken für HTTP-Anfragen und XML-Parsing beziehen:",[354,1713,1714,1731,1740],{},[39,1715,1716,1717,1720,1721,1723,1724,1727,1728,415],{},"Fehler: ",[239,1718,1719],{},"could not find blocking in reqwest",". Lösung: Aktiviere Funktion ",[239,1722,1120],{}," für Crate in ",[239,1725,1726],{},"Config.toml",": ",[239,1729,1730],{},"reqwest = { version = \"0.11.20\", features = [\"blocking\"] }",[39,1732,1716,1733,1736,1737,1739],{},[239,1734,1735],{},"failed to resolve: use of undeclared crate or module reqwest",". Lösung: Füge Crate ",[239,1738,1298],{}," hinzu.",[39,1741,1716,1742,1736,1745,1739],{},[239,1743,1744],{},"failed to resolve: use of undeclared crate or module roxmltree",[239,1746,1747],{},"roxmltree",[257,1749,1751],{"className":418,"code":1750,"language":420,"meta":262,"style":262},"vim Config.toml\n\nreqwest = { version = \"0.11.20\", features = [\"blocking\"] }\n",[239,1752,1753,1761,1765],{"__ignoreMap":262},[266,1754,1755,1758],{"class":268,"line":269},[266,1756,1757],{"class":427},"vim",[266,1759,1760],{"class":431}," Config.toml\n",[266,1762,1763],{"class":268,"line":276},[266,1764,446],{"emptyLinePlaceholder":445},[266,1766,1767,1769,1772,1775,1778,1780,1783,1786,1788,1791,1794],{"class":268,"line":285},[266,1768,1298],{"class":427},[266,1770,1771],{"class":431}," =",[266,1773,1774],{"class":431}," {",[266,1776,1777],{"class":431}," version",[266,1779,1771],{"class":431},[266,1781,1782],{"class":431}," \"0.11.20\",",[266,1784,1785],{"class":431}," features",[266,1787,1771],{"class":431},[266,1789,1790],{"class":550}," [",[266,1792,1793],{"class":431},"\"blocking\"",[266,1795,1796],{"class":550},"] }\n",[257,1798,1800],{"className":418,"code":1799,"language":420,"meta":262,"style":262},"cargo add reqwest\ncargo add roxmltree\n",[239,1801,1802,1811],{"__ignoreMap":262},[266,1803,1804,1806,1808],{"class":268,"line":269},[266,1805,452],{"class":427},[266,1807,472],{"class":431},[266,1809,1810],{"class":431}," reqwest\n",[266,1812,1813,1815,1817],{"class":268,"line":276},[266,1814,452],{"class":427},[266,1816,472],{"class":431},[266,1818,1819],{"class":431}," roxmltree\n",[12,1821,1822,1824,1825,1828],{},[252,1823,254],{}," Kopiere den Fehlermeldungs-String mit einem führenden ",[239,1826,1827],{},"Rust \u003Cerror message>"," in einen Browser, um zu sehen, ob eine fehlende Crate verfügbar ist. Allgemein führt diese Suche zu einem Ergebnis auf crates.io und du kannst die fehlenden Abhängigkeiten hinzufügen.",[12,1830,1831,1832,1835],{},"Wenn der Build erfolgreich ist, führe den Code mit ",[239,1833,1834],{},"cargo run"," aus und überprüfe die RSS-Feed-Ausgabe von Hacker News.",[12,1837,1838],{},[302,1839],{"alt":1840,"src":1841},"VS-Code-Terminal, cargo run zum Abrufen des XML-Feeds von Hacker News","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398629/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_fetch_rss_feed_output_hacker_news.png",[12,1843,1844],{},"Wie kann der XML-Body in ein für Menschen lesbares Format geparst werden? Als Nächstes lernen wir über bestehende Lösungen und Rust-Crates.",[214,1846,98],{"id":1847},"crates",[12,1849,1850],{},"RSS-Feeds haben gemeinsame Protokolle und Spezifikationen. Es fühlt sich an, als würde man das Rad neu erfinden, wenn man XML-Elemente parsen und die untere Objektstruktur verstehen will. Empfehlung: Schau nach, ob es dieses Problem samt Code schon gibt.",[12,1852,1853,1854,1860,1861,1863,1864,1867,1868,1871],{},"Der wiederverwendbare Bibliothekscode in Rust ist in ",[16,1855,1858],{"href":1856,"rel":1857},"https://doc.rust-lang.org/rust-by-example/crates.html",[],[239,1859,98],{}," organisiert und in Paketen/der Paket-Registry auf crates.io verfügbar. Füge diese Abhängigkeiten hinzu, indem du die Datei ",[239,1862,1726],{}," im Abschnitt ",[239,1865,1866],{},"[dependencies]"," bearbeitest oder ",[239,1869,1870],{},"cargo add \u003Cname>"," verwendest.",[12,1873,1874,1875,1880],{},"Für die Reader-App verwenden wir ",[16,1876,1879],{"href":1877,"rel":1878},"https://crates.io/crates/feed-rs",[],"Feed-rs-Crate",". Öffne ein neues Terminal, führe folgenden Befehl aus:",[257,1882,1884],{"className":418,"code":1883,"language":420,"meta":262,"style":262},"cargo add feed-rs\n",[239,1885,1886],{"__ignoreMap":262},[266,1887,1888,1890,1892],{"class":268,"line":269},[266,1889,452],{"class":427},[266,1891,472],{"class":431},[266,1893,1894],{"class":431}," feed-rs\n",[12,1896,1897],{},[302,1898],{"alt":1899,"src":1900},"VS-Code-Terminal: Crate hinzufügen, in Config.toml überprüfen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398627/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_rust_crate_add_feed-rs_explained.png",[232,1902,106],{"id":1903},"feed-rs-xml-feed-parsen",[12,1905,1906,1907,1910,1911,1914,1915,1918,1919,1921,1922,1927],{},"Gehe zu ",[239,1908,1909],{},"src/feed_reader.rs",", ändere den Teil, in dem wir den XML-Body parsen. Codevorschläge versteht, wie Crate ",[239,1912,1913],{},"feed-rs"," mit Funktion ",[239,1916,1917],{},"parser::parse"," aufgerufen wird, aber ",[239,1920,1913],{}," ",[16,1923,1926],{"href":1924,"rel":1925},"https://docs.rs/feed-rs/latest/feed_rs/parser/fn.parse_with_uri.html",[],"erwartet die String-Eingabe als Rohbytes",", um die Codierung selbst zu bestimmen. Wir können im Kommentar Anweisungen geben, um das erwartete Ergebnis zu erhalten.",[257,1929,1931],{"className":259,"code":1930,"language":261,"meta":262,"style":262},"            // Parse XML body with feed_rs parser, input in bytes\n            let parsed_body = feed_rs::parser::parse(body.as_bytes()).unwrap();\n",[239,1932,1933,1938],{"__ignoreMap":262},[266,1934,1935],{"class":268,"line":269},[266,1936,1937],{"class":272},"            // Parse XML body with feed_rs parser, input in bytes\n",[266,1939,1940,1942,1944,1946,1949,1951,1954,1956,1958,1961,1963,1966,1969,1971,1973],{"class":268,"line":276},[266,1941,1107],{"class":543},[266,1943,1168],{"class":550},[266,1945,675],{"class":543},[266,1947,1948],{"class":427}," feed_rs",[266,1950,625],{"class":543},[266,1952,1953],{"class":427},"parser",[266,1955,625],{"class":543},[266,1957,1183],{"class":427},[266,1959,1960],{"class":550},"(body",[266,1962,415],{"class":543},[266,1964,1965],{"class":427},"as_bytes",[266,1967,1968],{"class":550},"())",[266,1970,415],{"class":543},[266,1972,1133],{"class":427},[266,1974,1150],{"class":550},[12,1976,1977],{},[302,1978],{"alt":1979,"src":1980},"Codevorschläge: öffentliches Modul mit Funktion get_feeds(), Schritt 5: XML-Parser in feed-rs ändern","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398623/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_module_function_05_use_feed_rs_to_parse.png",[12,1982,1983,1984,1986,1987,1989],{},"Den Vorteil von ",[239,1985,1913],{}," siehst du im Ausdruck mit ",[239,1988,1834],{},": Alle Schlüssel/Werte werden ihren jeweiligen Rust-Objekttypen zugeordnet und können für weitere Operationen verwendet werden.",[12,1991,1992],{},[302,1993],{"alt":1840,"src":1994},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398629/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_fetch_rss_feed_output_hacker_news_feed_rs.png",[214,1996,112],{"id":1997},"laufzeit-konfiguration-programmargumente",[12,1999,2000],{},"Bisher haben wir das Programm mit hardcoded RSS-Feed-Werten ausgeführt, die in die Binärdatei kompiliert wurden. Jetzt wird der RSS-Feed zur Laufzeit konfiguriert.",[12,2002,2003,2004,2009,2010,2015,2016,2021,2022,2027],{},"Rust stellt in der Standard-Misc-Bibliothek ",[16,2005,2008],{"href":2006,"rel":2007},"https://doc.rust-lang.org/rust-by-example/std_misc/arg.html",[],"Programmargumente"," bereit. ",[16,2011,2014],{"href":2012,"rel":2013},"https://doc.rust-lang.org/rust-by-example/std_misc/arg/matching.html",[],"Argumente parsen"," ist besser und schneller als das Zielen auf erweiterte Programmargument-Parser (z. B. die Crate ",[16,2017,2020],{"href":2018,"rel":2019},"https://docs.rs/clap/latest/clap/",[],"clap",") oder das Verschieben der Programmparameter in eine Konfigurationsdatei/ein Format (",[16,2023,2026],{"href":2024,"rel":2025},"https://toml.io/en/",[],"TOML",", YAML). Vor diesem Blog habe ich Verschiedenes für die beste Lernerfahrung ausprobiert und versagt. Du kannst trotzdem versuchen, RSS-Feeds anders zu konfigurieren.",[12,2029,2030,2031,2034,2035,2038,2039,2041,2042,2045],{},"Als langweilige Lösung können Befehlsparameter als ",[239,2032,2033],{},"\"name,url\""," String-Wert-Paare übergeben und durch das ",[239,2036,2037],{},",","-Zeichen getrennt werden, um den Namen und die URL-Werte zu extrahieren. Der Kommentar weist Codevorschläge an, diese Vorgänge auszuführen und die HashMap ",[239,2040,591],{}," um die neuen Werte zu erweitern. Die Variable ist möglicherweise nicht veränderbar und muss in ",[239,2043,2044],{},"let mut rss_feeds"," geändert werden.",[12,2047,1906,2048,2050,2051,2053,2054,2056],{},[239,2049,521],{}," und füge der Funktion ",[239,2052,390],{}," nach der Variable ",[239,2055,591],{}," diesen Code hinzu. Beginne mit einem Kommentar, um die Programmargumente zu definieren, überprüfe die vorgeschlagenen Codeschnipsel.",[257,2058,2060],{"className":259,"code":2059,"language":261,"meta":262,"style":262},"    // Program args, format \"name,url\"\n    // Split value by , into name, url and add to rss_feeds\n",[239,2061,2062,2067],{"__ignoreMap":262},[266,2063,2064],{"class":268,"line":269},[266,2065,2066],{"class":272},"    // Program args, format \"name,url\"\n",[266,2068,2069],{"class":268,"line":276},[266,2070,2071],{"class":272},"    // Split value by , into name, url and add to rss_feeds\n",[12,2073,2074],{},[302,2075],{"alt":2076,"src":2077},"Codevorschläge für Programmargumente und Aufteilung von name,URL-Werten für die Variable rss_feeds","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398623/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_program_args_boring_solution.png",[12,2079,2080],{},"Vollständiges Codebeispiel:",[257,2082,2084],{"className":259,"code":2083,"language":261,"meta":262,"style":262},"fn main() {\n    // Define RSS feed URLs in the variable rss_feeds\n    // Use a HashMap\n    // Add Hacker News and TechCrunch\n    // Ensure to use String as type\n    let mut rss_feeds = HashMap::from([\n        (\"Hacker News\".to_string(), \"https://news.ycombinator.com/rss\".to_string()),\n        (\"TechCrunch\".to_string(), \"https://techcrunch.com/feed/\".to_string()),\n    ]);\n\n    // Program args, format \"name,url\"\n    // Split value by , into name, url and add to rss_feeds\n    for arg in std::env::args().skip(1) {\n        let mut split = arg.split(\",\");\n        let name = split.next().unwrap();\n        let url = split.next().unwrap();\n        rss_feeds.insert(name.to_string(), url.to_string());\n    }\n\n    // Call get_feeds() from feed_reader module\n    feed_reader::feed_reader::get_feeds(&rss_feeds);\n    // Alternative: Imported full path, use short path here.\n    //get_feeds(&rss_feeds);\n}\n",[239,2085,2086,2094,2098,2102,2106,2110,2129,2149,2169,2173,2177,2181,2185,2222,2250,2275,2298,2325,2329,2333,2337,2355,2360,2365],{"__ignoreMap":262},[266,2087,2088,2090,2092],{"class":268,"line":269},[266,2089,544],{"class":543},[266,2091,547],{"class":427},[266,2093,551],{"class":550},[266,2095,2096],{"class":268,"line":276},[266,2097,556],{"class":272},[266,2099,2100],{"class":268,"line":285},[266,2101,561],{"class":272},[266,2103,2104],{"class":268,"line":449},[266,2105,566],{"class":272},[266,2107,2108],{"class":268,"line":458},[266,2109,571],{"class":272},[266,2111,2112,2114,2117,2119,2121,2123,2125,2127],{"class":268,"line":463},[266,2113,669],{"class":543},[266,2115,2116],{"class":543}," mut",[266,2118,672],{"class":550},[266,2120,675],{"class":543},[266,2122,678],{"class":427},[266,2124,625],{"class":543},[266,2126,683],{"class":427},[266,2128,686],{"class":550},[266,2130,2131,2133,2135,2137,2139,2141,2143,2145,2147],{"class":268,"line":481},[266,2132,692],{"class":550},[266,2134,695],{"class":431},[266,2136,415],{"class":543},[266,2138,700],{"class":427},[266,2140,703],{"class":550},[266,2142,706],{"class":431},[266,2144,415],{"class":543},[266,2146,700],{"class":427},[266,2148,713],{"class":550},[266,2150,2151,2153,2155,2157,2159,2161,2163,2165,2167],{"class":268,"line":666},[266,2152,692],{"class":550},[266,2154,721],{"class":431},[266,2156,415],{"class":543},[266,2158,700],{"class":427},[266,2160,703],{"class":550},[266,2162,730],{"class":431},[266,2164,415],{"class":543},[266,2166,700],{"class":427},[266,2168,713],{"class":550},[266,2170,2171],{"class":268,"line":689},[266,2172,742],{"class":550},[266,2174,2175],{"class":268,"line":716},[266,2176,446],{"emptyLinePlaceholder":445},[266,2178,2179],{"class":268,"line":739},[266,2180,2066],{"class":272},[266,2182,2183],{"class":268,"line":745},[266,2184,2071],{"class":272},[266,2186,2187,2190,2193,2195,2197,2199,2202,2204,2207,2209,2211,2214,2216,2219],{"class":268,"line":750},[266,2188,2189],{"class":543},"    for",[266,2191,2192],{"class":550}," arg ",[266,2194,1076],{"class":543},[266,2196,622],{"class":427},[266,2198,625],{"class":543},[266,2200,2201],{"class":427},"env",[266,2203,625],{"class":543},[266,2205,2206],{"class":427},"args",[266,2208,1136],{"class":550},[266,2210,415],{"class":543},[266,2212,2213],{"class":427},"skip",[266,2215,1087],{"class":550},[266,2217,2218],{"class":437},"1",[266,2220,2221],{"class":550},") {\n",[266,2223,2224,2227,2229,2232,2234,2237,2239,2242,2244,2247],{"class":268,"line":1157},[266,2225,2226],{"class":543},"        let",[266,2228,2116],{"class":543},[266,2230,2231],{"class":550}," split ",[266,2233,675],{"class":543},[266,2235,2236],{"class":550}," arg",[266,2238,415],{"class":543},[266,2240,2241],{"class":427},"split",[266,2243,1087],{"class":550},[266,2245,2246],{"class":431},"\",\"",[266,2248,2249],{"class":550},");\n",[266,2251,2252,2254,2257,2259,2262,2264,2267,2269,2271,2273],{"class":268,"line":1163},[266,2253,2226],{"class":543},[266,2255,2256],{"class":550}," name ",[266,2258,675],{"class":543},[266,2260,2261],{"class":550}," split",[266,2263,415],{"class":543},[266,2265,2266],{"class":427},"next",[266,2268,1136],{"class":550},[266,2270,415],{"class":543},[266,2272,1133],{"class":427},[266,2274,1150],{"class":550},[266,2276,2277,2279,2282,2284,2286,2288,2290,2292,2294,2296],{"class":268,"line":1200},[266,2278,2226],{"class":543},[266,2280,2281],{"class":550}," url ",[266,2283,675],{"class":543},[266,2285,2261],{"class":550},[266,2287,415],{"class":543},[266,2289,2266],{"class":427},[266,2291,1136],{"class":550},[266,2293,415],{"class":543},[266,2295,1133],{"class":427},[266,2297,1150],{"class":550},[266,2299,2300,2303,2305,2308,2311,2313,2315,2318,2320,2322],{"class":268,"line":1205},[266,2301,2302],{"class":550},"        rss_feeds",[266,2304,415],{"class":543},[266,2306,2307],{"class":427},"insert",[266,2309,2310],{"class":550},"(name",[266,2312,415],{"class":543},[266,2314,700],{"class":427},[266,2316,2317],{"class":550},"(), url",[266,2319,415],{"class":543},[266,2321,700],{"class":427},[266,2323,2324],{"class":550},"());\n",[266,2326,2327],{"class":268,"line":1211},[266,2328,930],{"class":550},[266,2330,2331],{"class":268,"line":1224},[266,2332,446],{"emptyLinePlaceholder":445},[266,2334,2335],{"class":268,"line":1230},[266,2336,1658],{"class":272},[266,2338,2339,2341,2343,2345,2347,2349,2351,2353],{"class":268,"line":1235},[266,2340,1395],{"class":427},[266,2342,625],{"class":543},[266,2344,811],{"class":427},[266,2346,625],{"class":543},[266,2348,1404],{"class":427},[266,2350,1087],{"class":550},[266,2352,1188],{"class":543},[266,2354,1411],{"class":550},[266,2356,2358],{"class":268,"line":2357},22,[266,2359,1681],{"class":272},[266,2361,2363],{"class":268,"line":2362},23,[266,2364,1686],{"class":272},[266,2366,2368],{"class":268,"line":2367},24,[266,2369,580],{"class":550},[12,2371,2372,2373,2375,2376,2379,2380,2382],{},"Du kannst Programmargumente direkt an den Befehl ",[239,2374,1834],{}," übergeben, wobei den Argumenten ",[239,2377,2378],{},"--"," vorgestellt ist.\n",[239,2381,2378],{},". Füge alle Argumente mit doppelten Anführungszeichen und den Namen gefolgt von einem Komma und den RSS-Feed-URL als Argument ein. Trenne alle Argumente mit Leerzeichen.",[257,2384,2386],{"className":418,"code":2385,"language":420,"meta":262,"style":262},"cargo build\n\ncargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n",[239,2387,2388,2394,2398],{"__ignoreMap":262},[266,2389,2390,2392],{"class":268,"line":269},[266,2391,452],{"class":427},[266,2393,1708],{"class":431},[266,2395,2396],{"class":268,"line":276},[266,2397,446],{"emptyLinePlaceholder":445},[266,2399,2400,2402,2405,2408,2411],{"class":268,"line":285},[266,2401,452],{"class":427},[266,2403,2404],{"class":431}," run",[266,2406,2407],{"class":437}," --",[266,2409,2410],{"class":431}," \"GitLab Blog,https://about.gitlab.com/atom.xml\"",[266,2412,2413],{"class":431}," \"CNCF,https://www.cncf.io/feed/\"\n",[12,2415,2416],{},[302,2417],{"alt":2418,"src":2419},"VS-Code-Terminal, Beispiel einer RSS-Feed-Ausgabe für den GitLab-Blog","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398630/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_gitlab_blog_rss_feed_example.png",[232,2421,2423],{"id":2422},"fehlerbehandlung-bei-benutzereingaben","Fehlerbehandlung bei Benutzereingaben",[12,2425,2426,2427,2432],{},"Wenn die Benutzereingabe nicht der Programmerwartung entspricht, müssen wir ",[16,2428,2431],{"href":2429,"rel":2430},"https://doc.rust-lang.org/rust-by-example/error.html",[],"einen Fehler ausgeben"," und dem Caller helfen, die Programmargumente zu beheben. Die Übergabe eines fehlerhaften URL-Formats sollte als Laufzeitfehler behandelt werden. Weise Codevorschläge an, einen Fehler auszugeben, wenn die URL nicht gültig ist.",[257,2434,2436],{"className":259,"code":2435,"language":261,"meta":262,"style":262},"    // Ensure that URL contains a valid format, otherwise throw an error\n",[239,2437,2438],{"__ignoreMap":262},[266,2439,2440],{"class":268,"line":269},[266,2441,2435],{"class":272},[12,2443,2444,2445,2448,2449,1265,2452,2455,2456,2461],{},"Mögliche Lösung: Beginnt die Variable ",[239,2446,2447],{},"url"," mit ",[239,2450,2451],{},"http://",[239,2453,2454],{},"https://","? Wenn nicht, gib einen Fehler mit dem Makro ",[16,2457,2460],{"href":2458,"rel":2459},"https://doc.rust-lang.org/rust-by-example/std/panic.html",[],"Panic! "," aus. Vollständiges Codebeispiel:",[257,2463,2465],{"className":259,"code":2464,"language":261,"meta":262,"style":262},"    // Program args, format \"name,url\"\n    // Split value by , into name, url and add to rss_feeds\n    for arg in std::env::args().skip(1) {\n        let mut split = arg.split(\",\");\n        let name = split.next().unwrap();\n        let url = split.next().unwrap();\n\n        // Ensure that URL contains a valid format, otherwise throw an error\n        if !url.starts_with(\"http://\") && !url.starts_with(\"https://\") {\n            panic!(\"Invalid URL format: {}\", url);\n        }\n\n        rss_feeds.insert(name.to_string(), url.to_string());\n    }\n",[239,2466,2467,2471,2475,2505,2527,2549,2571,2575,2580,2621,2634,2638,2642,2664],{"__ignoreMap":262},[266,2468,2469],{"class":268,"line":269},[266,2470,2066],{"class":272},[266,2472,2473],{"class":268,"line":276},[266,2474,2071],{"class":272},[266,2476,2477,2479,2481,2483,2485,2487,2489,2491,2493,2495,2497,2499,2501,2503],{"class":268,"line":285},[266,2478,2189],{"class":543},[266,2480,2192],{"class":550},[266,2482,1076],{"class":543},[266,2484,622],{"class":427},[266,2486,625],{"class":543},[266,2488,2201],{"class":427},[266,2490,625],{"class":543},[266,2492,2206],{"class":427},[266,2494,1136],{"class":550},[266,2496,415],{"class":543},[266,2498,2213],{"class":427},[266,2500,1087],{"class":550},[266,2502,2218],{"class":437},[266,2504,2221],{"class":550},[266,2506,2507,2509,2511,2513,2515,2517,2519,2521,2523,2525],{"class":268,"line":449},[266,2508,2226],{"class":543},[266,2510,2116],{"class":543},[266,2512,2231],{"class":550},[266,2514,675],{"class":543},[266,2516,2236],{"class":550},[266,2518,415],{"class":543},[266,2520,2241],{"class":427},[266,2522,1087],{"class":550},[266,2524,2246],{"class":431},[266,2526,2249],{"class":550},[266,2528,2529,2531,2533,2535,2537,2539,2541,2543,2545,2547],{"class":268,"line":458},[266,2530,2226],{"class":543},[266,2532,2256],{"class":550},[266,2534,675],{"class":543},[266,2536,2261],{"class":550},[266,2538,415],{"class":543},[266,2540,2266],{"class":427},[266,2542,1136],{"class":550},[266,2544,415],{"class":543},[266,2546,1133],{"class":427},[266,2548,1150],{"class":550},[266,2550,2551,2553,2555,2557,2559,2561,2563,2565,2567,2569],{"class":268,"line":463},[266,2552,2226],{"class":543},[266,2554,2281],{"class":550},[266,2556,675],{"class":543},[266,2558,2261],{"class":550},[266,2560,415],{"class":543},[266,2562,2266],{"class":427},[266,2564,1136],{"class":550},[266,2566,415],{"class":543},[266,2568,1133],{"class":427},[266,2570,1150],{"class":550},[266,2572,2573],{"class":268,"line":481},[266,2574,446],{"emptyLinePlaceholder":445},[266,2576,2577],{"class":268,"line":666},[266,2578,2579],{"class":272},"        // Ensure that URL contains a valid format, otherwise throw an error\n",[266,2581,2582,2585,2588,2590,2592,2595,2597,2600,2603,2606,2608,2610,2612,2614,2616,2619],{"class":268,"line":689},[266,2583,2584],{"class":543},"        if",[266,2586,2587],{"class":543}," !",[266,2589,2447],{"class":550},[266,2591,415],{"class":543},[266,2593,2594],{"class":427},"starts_with",[266,2596,1087],{"class":550},[266,2598,2599],{"class":431},"\"http://\"",[266,2601,2602],{"class":550},") ",[266,2604,2605],{"class":543},"&&",[266,2607,2587],{"class":543},[266,2609,2447],{"class":550},[266,2611,415],{"class":543},[266,2613,2594],{"class":427},[266,2615,1087],{"class":550},[266,2617,2618],{"class":431},"\"https://\"",[266,2620,2221],{"class":550},[266,2622,2623,2626,2628,2631],{"class":268,"line":716},[266,2624,2625],{"class":427},"            panic!",[266,2627,1087],{"class":550},[266,2629,2630],{"class":431},"\"Invalid URL format: {}\"",[266,2632,2633],{"class":550},", url);\n",[266,2635,2636],{"class":268,"line":739},[266,2637,1227],{"class":550},[266,2639,2640],{"class":268,"line":745},[266,2641,446],{"emptyLinePlaceholder":445},[266,2643,2644,2646,2648,2650,2652,2654,2656,2658,2660,2662],{"class":268,"line":750},[266,2645,2302],{"class":550},[266,2647,415],{"class":543},[266,2649,2307],{"class":427},[266,2651,2310],{"class":550},[266,2653,415],{"class":543},[266,2655,700],{"class":427},[266,2657,2317],{"class":550},[266,2659,415],{"class":543},[266,2661,700],{"class":427},[266,2663,2324],{"class":550},[266,2665,2666],{"class":268,"line":1157},[266,2667,930],{"class":550},[12,2669,2670,2671,2673,2674,2677,2678,2681],{},"Teste, was passiert, wenn du ein ",[239,2672,901],{}," in einem URL-String entfernst. Füge die Umgebungsvariable ",[239,2675,2676],{},"RUST_BACKTRACE=full"," hinzu, um beim Aufruf von ",[239,2679,2680],{},"panic()"," eine ausführlichere Ausgabe zu erhalten.",[257,2683,2685],{"className":418,"code":2684,"language":420,"meta":262,"style":262},"RUST_BACKTRACE=full cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https//www.cncf.io/feed/\"\n",[239,2686,2687],{"__ignoreMap":262},[266,2688,2689,2692,2694,2697,2700,2702,2704,2706],{"class":268,"line":269},[266,2690,2691],{"class":550},"RUST_BACKTRACE",[266,2693,675],{"class":543},[266,2695,2696],{"class":431},"full",[266,2698,2699],{"class":427}," cargo",[266,2701,2404],{"class":431},[266,2703,2407],{"class":437},[266,2705,2410],{"class":431},[266,2707,2708],{"class":431}," \"CNCF,https//www.cncf.io/feed/\"\n",[12,2710,2711],{},[302,2712],{"alt":2713,"src":2714},"VS-Code-Terminal mit falschem URL-Format, panic-Fehler-Backtrace","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398630/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_url_format_error_panic_backtrace.png",[214,2716,126],{"id":2717},"persistenz-und-datenspeicherung",[12,2719,2720],{},"Bei der langweiligen Lösung zum Speichern der Feed-Daten wird der geparste Body in eine neue Datei kopiert. Weise Codevorschläge an, ein Muster zu verwenden, das den RSS-Feed-Namen und das aktuelle ISO-Datum enthält.",[257,2722,2724],{"className":259,"code":2723,"language":261,"meta":262,"style":262},"    // Parse XML body with feed_rs parser, input in bytes\n    let parsed_body = feed_rs::parser::parse(body.as_bytes()).unwrap();\n\n    // Print the result\n    println!(\"{:#?}\", parsed_body);\n\n    // Dump the parsed body to a file, as name-current-iso-date.xml\n    let now = chrono::offset::Local::now();\n    let filename = format!(\"{}-{}.xml\", name, now.format(\"%Y-%m-%d\"));\n    let mut file = std::fs::File::create(filename).unwrap();\n    file.write_all(body.as_bytes()).unwrap();\n",[239,2725,2726,2731,2763,2767,2772,2783,2787,2792,2821,2854,2891],{"__ignoreMap":262},[266,2727,2728],{"class":268,"line":269},[266,2729,2730],{"class":272},"    // Parse XML body with feed_rs parser, input in bytes\n",[266,2732,2733,2735,2737,2739,2741,2743,2745,2747,2749,2751,2753,2755,2757,2759,2761],{"class":268,"line":276},[266,2734,669],{"class":543},[266,2736,1168],{"class":550},[266,2738,675],{"class":543},[266,2740,1948],{"class":427},[266,2742,625],{"class":543},[266,2744,1953],{"class":427},[266,2746,625],{"class":543},[266,2748,1183],{"class":427},[266,2750,1960],{"class":550},[266,2752,415],{"class":543},[266,2754,1965],{"class":427},[266,2756,1968],{"class":550},[266,2758,415],{"class":543},[266,2760,1133],{"class":427},[266,2762,1150],{"class":550},[266,2764,2765],{"class":268,"line":285},[266,2766,446],{"emptyLinePlaceholder":445},[266,2768,2769],{"class":268,"line":449},[266,2770,2771],{"class":272},"    // Print the result\n",[266,2773,2774,2777,2779,2781],{"class":268,"line":458},[266,2775,2776],{"class":427},"    println!",[266,2778,1087],{"class":550},[266,2780,1218],{"class":431},[266,2782,1221],{"class":550},[266,2784,2785],{"class":268,"line":463},[266,2786,446],{"emptyLinePlaceholder":445},[266,2788,2789],{"class":268,"line":481},[266,2790,2791],{"class":272},"    // Dump the parsed body to a file, as name-current-iso-date.xml\n",[266,2793,2794,2796,2799,2801,2804,2806,2809,2811,2814,2816,2819],{"class":268,"line":666},[266,2795,669],{"class":543},[266,2797,2798],{"class":550}," now ",[266,2800,675],{"class":543},[266,2802,2803],{"class":427}," chrono",[266,2805,625],{"class":543},[266,2807,2808],{"class":427},"offset",[266,2810,625],{"class":543},[266,2812,2813],{"class":427},"Local",[266,2815,625],{"class":543},[266,2817,2818],{"class":427},"now",[266,2820,1150],{"class":550},[266,2822,2823,2825,2828,2830,2833,2835,2838,2841,2843,2846,2848,2851],{"class":268,"line":689},[266,2824,669],{"class":543},[266,2826,2827],{"class":550}," filename ",[266,2829,675],{"class":543},[266,2831,2832],{"class":427}," format!",[266,2834,1087],{"class":550},[266,2836,2837],{"class":431},"\"{}-{}.xml\"",[266,2839,2840],{"class":550},", name, now",[266,2842,415],{"class":543},[266,2844,2845],{"class":427},"format",[266,2847,1087],{"class":550},[266,2849,2850],{"class":431},"\"%Y-%m-%d\"",[266,2852,2853],{"class":550},"));\n",[266,2855,2856,2858,2860,2863,2865,2867,2869,2872,2874,2877,2879,2882,2885,2887,2889],{"class":268,"line":716},[266,2857,669],{"class":543},[266,2859,2116],{"class":543},[266,2861,2862],{"class":550}," file ",[266,2864,675],{"class":543},[266,2866,622],{"class":427},[266,2868,625],{"class":543},[266,2870,2871],{"class":427},"fs",[266,2873,625],{"class":543},[266,2875,2876],{"class":427},"File",[266,2878,625],{"class":543},[266,2880,2881],{"class":427},"create",[266,2883,2884],{"class":550},"(filename)",[266,2886,415],{"class":543},[266,2888,1133],{"class":427},[266,2890,1150],{"class":550},[266,2892,2893,2896,2898,2901,2903,2905,2907,2909,2911,2913],{"class":268,"line":739},[266,2894,2895],{"class":550},"    file",[266,2897,415],{"class":543},[266,2899,2900],{"class":427},"write_all",[266,2902,1960],{"class":550},[266,2904,415],{"class":543},[266,2906,1965],{"class":427},[266,2908,1968],{"class":550},[266,2910,415],{"class":543},[266,2912,1133],{"class":427},[266,2914,1150],{"class":550},[12,2916,2917,2918,2923,2924,2927,2928,225,2930,2932],{},"Ein möglicher Vorschlag ist die Verwendung der ",[16,2919,2922],{"href":2920,"rel":2921},"https://crates.io/crates/chrono",[],"Crate chrono",". Füge sie mit ",[239,2925,2926],{},"cargo add chrono"," hinzu, rufe wieder ",[239,2929,768],{},[239,2931,1834],{}," auf.",[12,2934,2935,2936,2938,2939,2942],{},"Die Dateien werden in das gleiche Verzeichnis geschrieben, in dem ",[239,2937,1834],{}," ausgeführt wurde. Wenn du die Binärdatei direkt im Verzeichnis ",[239,2940,2941],{},"target/debug/"," ausführst, werden alle Dateien dort abgelegt.",[12,2944,2945],{},[302,2946],{"alt":2947,"src":2948},"VS-Code mit CNCF-RSS-Feed-Inhaltsdatei, auf Festplatte gespeichert","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398626/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_cncf_rss_feed_saved_on_disk.png",[214,2950,132],{"id":2951},"optimierung",[12,2953,2954,2955,2957],{},"Die Einträge in der Variable ",[239,2956,591],{}," werden nacheinander ausgeführt. Bei einer Liste mit über 100 konfigurierten URLs kann das Abrufen und Verarbeiten lange dauern. Was wäre, wenn Abrufanforderungen parallel ausgeführt würden?",[232,2959,140],{"id":2960},"asynchrone-ausführung",[12,2962,2963,2964,2969],{},"Rust stellt ",[16,2965,2968],{"href":2966,"rel":2967},"https://doc.rust-lang.org/book/ch16-01-threads.html",[],"Threads"," für die asynchrone Ausführung bereit.",[12,2971,2972,2973,2975,2976,2979],{},"Bei der einfachsten Lösung wird für jede RSS-Feed-URL ein Thread erstellt. Wir sprechen später über Optimierungsstrategien. Vor der parallelen Ausführung musst du die Ausführungszeit des sequentiellen Codes mit dem Befehl ",[239,2974,1834],{}," vor ",[239,2977,2978],{},"time"," messen.",[257,2981,2984],{"className":2982,"code":2983,"language":1141,"meta":262},[1338],"time cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n\n0.21s user 0.08s system 10% cpu 2.898 total\n",[239,2985,2983],{"__ignoreMap":262},[12,2987,2988,2989,2992],{},"Beachte, dass diese Übung mehr manuelle Codearbeit erfordern könnte. Empfehlung: Den sequentiellen Arbeitszustand in einem neuen Git-Commit und einem neuen Git-Branch ",[239,2990,2991],{},"sequential-exec"," beibehalten, um die Auswirkungen der parallelen Ausführung besser zu vergleichen.",[257,2994,2996],{"className":418,"code":2995,"language":420,"meta":262,"style":262},"git commit -avm \"Sequential execution working\"\ngit checkout -b sequential-exec\ngit push -u origin sequential-exec\n\ngit checkout main\n",[239,2997,2998,3011,3024,3037,3041],{"__ignoreMap":262},[266,2999,3000,3002,3005,3008],{"class":268,"line":269},[266,3001,466],{"class":427},[266,3003,3004],{"class":431}," commit",[266,3006,3007],{"class":437}," -avm",[266,3009,3010],{"class":431}," \"Sequential execution working\"\n",[266,3012,3013,3015,3018,3021],{"class":268,"line":276},[266,3014,466],{"class":427},[266,3016,3017],{"class":431}," checkout",[266,3019,3020],{"class":437}," -b",[266,3022,3023],{"class":431}," sequential-exec\n",[266,3025,3026,3028,3030,3033,3035],{"class":268,"line":285},[266,3027,466],{"class":427},[266,3029,486],{"class":431},[266,3031,3032],{"class":437}," -u",[266,3034,475],{"class":431},[266,3036,3023],{"class":431},[266,3038,3039],{"class":268,"line":449},[266,3040,446],{"emptyLinePlaceholder":445},[266,3042,3043,3045,3047],{"class":268,"line":458},[266,3044,466],{"class":427},[266,3046,3017],{"class":431},[266,3048,494],{"class":431},[232,3050,146],{"id":3051},"threads-spawnen",[12,3053,3054,3055,3057,3058,3060],{},"Öffne ",[239,3056,1909],{}," und refaktorisiere die Funktion ",[239,3059,796],{},". Beginne mit einem Git-Commit für den aktuellen Status und lösche dann den Inhalt des Funktionsbereichs. Füge die folgenden Codekommentare hinzu:",[354,3062,3063,3069],{},[39,3064,3065,3068],{},[239,3066,3067],{},"// Store threads in vector",": Speichere die Thread-Alias in einem Vektor, damit wir warten können, bis sie am Ende des Funktionsaufrufs abgeschlossen sind.",[39,3070,3071,3074],{},[239,3072,3073],{},"// Loop over rss_feeds and spawn threads",": Erstelle Boilerplate-Code für die Iteration über alle RSS-Feeds und einen neuen Thread.",[12,3076,3077,3078,3080,3081,225,3084,3086],{},"Füge die folgenden ",[239,3079,619],{},"-Anweisungen hinzu, um mit den Modulen ",[239,3082,3083],{},"thread",[239,3085,2978],{}," zu arbeiten.",[257,3088,3090],{"className":259,"code":3089,"language":261,"meta":262,"style":262},"    use std::thread;\n    use std::time::Duration;\n",[239,3091,3092,3103],{"__ignoreMap":262},[266,3093,3094,3096,3098,3100],{"class":268,"line":269},[266,3095,868],{"class":543},[266,3097,622],{"class":427},[266,3099,625],{"class":543},[266,3101,3102],{"class":550},"thread;\n",[266,3104,3105,3107,3109,3111,3113,3115,3118],{"class":268,"line":276},[266,3106,868],{"class":543},[266,3108,622],{"class":427},[266,3110,625],{"class":543},[266,3112,2978],{"class":427},[266,3114,625],{"class":543},[266,3116,3117],{"class":427},"Duration",[266,3119,635],{"class":550},[12,3121,3122,3123,3126],{},"Schreibe den Code weiter, schließe die for-Schleife. Codevorschläge schlägt dann automatisch vor, das Thread-Alias in der Vektorvariable ",[239,3124,3125],{},"threads"," hinzuzufügen und bietet an, den Threads am Ende der Funktion beizutreten.",[257,3128,3130],{"className":259,"code":3129,"language":261,"meta":262,"style":262},"    pub fn get_feeds(rss_feeds: &HashMap\u003CString, String>) {\n\n        // Store threads in vector\n        let mut threads: Vec\u003Cthread::JoinHandle\u003C()>> = Vec::new();\n\n        // Loop over rss_feeds and spawn threads\n        for (name, url) in rss_feeds {\n            let thread_name = name.clone();\n            let thread_url = url.clone();\n            let thread = thread::spawn(move || {\n\n            });\n            threads.push(thread);\n        }\n\n        // Join threads\n        for thread in threads {\n            thread.join().unwrap();\n        }\n    }\n",[239,3131,3132,3158,3162,3167,3203,3207,3212,3222,3241,3259,3286,3290,3295,3308,3312,3316,3321,3332,3350,3354],{"__ignoreMap":262},[266,3133,3134,3136,3138,3140,3142,3144,3146,3148,3150,3152,3154,3156],{"class":268,"line":269},[266,3135,889],{"class":543},[266,3137,892],{"class":543},[266,3139,895],{"class":427},[266,3141,898],{"class":550},[266,3143,901],{"class":543},[266,3145,904],{"class":543},[266,3147,532],{"class":427},[266,3149,909],{"class":550},[266,3151,912],{"class":427},[266,3153,915],{"class":550},[266,3155,912],{"class":427},[266,3157,920],{"class":550},[266,3159,3160],{"class":268,"line":276},[266,3161,446],{"emptyLinePlaceholder":445},[266,3163,3164],{"class":268,"line":285},[266,3165,3166],{"class":272},"        // Store threads in vector\n",[266,3168,3169,3171,3173,3176,3178,3181,3184,3186,3189,3192,3194,3196,3198,3201],{"class":268,"line":449},[266,3170,2226],{"class":543},[266,3172,2116],{"class":543},[266,3174,3175],{"class":550}," threads",[266,3177,901],{"class":543},[266,3179,3180],{"class":427}," Vec",[266,3182,3183],{"class":550},"\u003Cthread",[266,3185,625],{"class":543},[266,3187,3188],{"class":427},"JoinHandle",[266,3190,3191],{"class":550},"\u003C()>> ",[266,3193,675],{"class":543},[266,3195,3180],{"class":427},[266,3197,625],{"class":543},[266,3199,3200],{"class":427},"new",[266,3202,1150],{"class":550},[266,3204,3205],{"class":268,"line":458},[266,3206,446],{"emptyLinePlaceholder":445},[266,3208,3209],{"class":268,"line":463},[266,3210,3211],{"class":272},"        // Loop over rss_feeds and spawn threads\n",[266,3213,3214,3216,3218,3220],{"class":268,"line":481},[266,3215,1070],{"class":543},[266,3217,1073],{"class":550},[266,3219,1076],{"class":543},[266,3221,1079],{"class":550},[266,3223,3224,3226,3229,3231,3234,3236,3239],{"class":268,"line":666},[266,3225,1107],{"class":543},[266,3227,3228],{"class":550}," thread_name ",[266,3230,675],{"class":543},[266,3232,3233],{"class":550}," name",[266,3235,415],{"class":543},[266,3237,3238],{"class":427},"clone",[266,3240,1150],{"class":550},[266,3242,3243,3245,3248,3250,3253,3255,3257],{"class":268,"line":689},[266,3244,1107],{"class":543},[266,3246,3247],{"class":550}," thread_url ",[266,3249,675],{"class":543},[266,3251,3252],{"class":550}," url",[266,3254,415],{"class":543},[266,3256,3238],{"class":427},[266,3258,1150],{"class":550},[266,3260,3261,3263,3266,3268,3271,3273,3276,3278,3281,3284],{"class":268,"line":716},[266,3262,1107],{"class":543},[266,3264,3265],{"class":550}," thread ",[266,3267,675],{"class":543},[266,3269,3270],{"class":427}," thread",[266,3272,625],{"class":543},[266,3274,3275],{"class":427},"spawn",[266,3277,1087],{"class":550},[266,3279,3280],{"class":543},"move",[266,3282,3283],{"class":543}," ||",[266,3285,863],{"class":550},[266,3287,3288],{"class":268,"line":739},[266,3289,446],{"emptyLinePlaceholder":445},[266,3291,3292],{"class":268,"line":745},[266,3293,3294],{"class":550},"            });\n",[266,3296,3297,3300,3302,3305],{"class":268,"line":750},[266,3298,3299],{"class":550},"            threads",[266,3301,415],{"class":543},[266,3303,3304],{"class":427},"push",[266,3306,3307],{"class":550},"(thread);\n",[266,3309,3310],{"class":268,"line":1157},[266,3311,1227],{"class":550},[266,3313,3314],{"class":268,"line":1163},[266,3315,446],{"emptyLinePlaceholder":445},[266,3317,3318],{"class":268,"line":1200},[266,3319,3320],{"class":272},"        // Join threads\n",[266,3322,3323,3325,3327,3329],{"class":268,"line":1205},[266,3324,1070],{"class":543},[266,3326,3265],{"class":550},[266,3328,1076],{"class":543},[266,3330,3331],{"class":550}," threads {\n",[266,3333,3334,3337,3339,3342,3344,3346,3348],{"class":268,"line":1211},[266,3335,3336],{"class":550},"            thread",[266,3338,415],{"class":543},[266,3340,3341],{"class":427},"join",[266,3343,1136],{"class":550},[266,3345,415],{"class":543},[266,3347,1133],{"class":427},[266,3349,1150],{"class":550},[266,3351,3352],{"class":268,"line":1224},[266,3353,1227],{"class":550},[266,3355,3356],{"class":268,"line":1230},[266,3357,930],{"class":550},[12,3359,3360,3361,3363],{},"Füge die Crate ",[239,3362,3083],{}," hinzu, erstelle den Code, führe ihn erneut aus.",[257,3365,3367],{"className":418,"code":3366,"language":420,"meta":262,"style":262},"cargo add thread\n\ncargo build\n\ncargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n",[239,3368,3369,3378,3382,3388,3392],{"__ignoreMap":262},[266,3370,3371,3373,3375],{"class":268,"line":269},[266,3372,452],{"class":427},[266,3374,472],{"class":431},[266,3376,3377],{"class":431}," thread\n",[266,3379,3380],{"class":268,"line":276},[266,3381,446],{"emptyLinePlaceholder":445},[266,3383,3384,3386],{"class":268,"line":285},[266,3385,452],{"class":427},[266,3387,1708],{"class":431},[266,3389,3390],{"class":268,"line":449},[266,3391,446],{"emptyLinePlaceholder":445},[266,3393,3394,3396,3398,3400,3402],{"class":268,"line":458},[266,3395,452],{"class":427},[266,3397,2404],{"class":431},[266,3399,2407],{"class":437},[266,3401,2410],{"class":431},[266,3403,2413],{"class":431},[12,3405,3406],{},"Zu diesem Zeitpunkt werden keine Daten verarbeitet oder gedruckt. Bevor wir die Funktion erneut hinzufügen, informieren wir uns über die neu eingeführten Keywords.",[232,3408,3410],{"id":3409},"funktionsumfänge-threads-und-closures","Funktionsumfänge, Threads und Closures",[12,3412,3413,3414,3417,3418,3423],{},"Mit dem vorgeschlagenen Code gilt es neue Keywords und Designmuster zu erlernen. Der Thread-Alias hat den Typ ",[239,3415,3416],{},"thread:: JoinHandle",", wir können also warten, bis die Threads (",[16,3419,3422],{"href":3420,"rel":3421},"https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles",[],"join()",") beendet haben.",[12,3425,3426,3429,3430,3435,3436,3439,3440,3447],{},[239,3427,3428],{},"thread::spawn()"," erstellt einen neuen Thread, in dem wir ein Funktionsobjekt übergeben können. In diesem Fall wird der Ausdruck ",[16,3431,3434],{"href":3432,"rel":3433},"https://doc.rust-lang.org/book/ch13-01-closures.html",[],"closure"," als anonyme Funktion übergeben. Closure-Eingaben werden mit der Syntax ",[239,3437,3438],{},"||"," übergeben. Du erkennst den ",[16,3441,3444,3445],{"href":3442,"rel":3443},"https://doc.rust-lang.org/book/ch16-01-threads.html#using-move-closures-with-threads",[],"Closure ",[239,3446,3280],{},", der die Variablen des Funktionsbereichs in den Thread-Bereich verschiebt. Dadurch wird die manuelle Angabe vermieden, welche Variablen in den neuen Funktions-/Closure-Bereich übergeben werden müssen.",[12,3449,3450,3451,3453,3454,3456,3457,3459],{},"Einschränkung: ",[239,3452,591],{}," ist eine Referenz ",[239,3455,1188],{},", die vom Funktions-Caller ",[239,3458,796],{}," als Parameter übergeben wird. Die Variable ist nur im Funktionsbereich gültig. Provoziere diesen Fehler mit diesem Codeausschnitt:",[257,3461,3463],{"className":259,"code":3462,"language":261,"meta":262,"style":262},"pub fn get_feeds(rss_feeds: &HashMap\u003CString, String>) {\n\n    // Store threads in vector\n    let mut threads: Vec\u003Cthread::JoinHandle\u003C()>> = Vec::new();\n\n    // Loop over rss_feeds and spawn threads\n    for (key, value) in rss_feeds {\n        let thread = thread::spawn(move || {\n            println!(\"{}\", key);\n        });\n    }\n}\n",[239,3464,3465,3491,3495,3500,3530,3534,3539,3550,3572,3584,3589,3593],{"__ignoreMap":262},[266,3466,3467,3469,3471,3473,3475,3477,3479,3481,3483,3485,3487,3489],{"class":268,"line":269},[266,3468,854],{"class":543},[266,3470,892],{"class":543},[266,3472,895],{"class":427},[266,3474,898],{"class":550},[266,3476,901],{"class":543},[266,3478,904],{"class":543},[266,3480,532],{"class":427},[266,3482,909],{"class":550},[266,3484,912],{"class":427},[266,3486,915],{"class":550},[266,3488,912],{"class":427},[266,3490,920],{"class":550},[266,3492,3493],{"class":268,"line":276},[266,3494,446],{"emptyLinePlaceholder":445},[266,3496,3497],{"class":268,"line":285},[266,3498,3499],{"class":272},"    // Store threads in vector\n",[266,3501,3502,3504,3506,3508,3510,3512,3514,3516,3518,3520,3522,3524,3526,3528],{"class":268,"line":449},[266,3503,669],{"class":543},[266,3505,2116],{"class":543},[266,3507,3175],{"class":550},[266,3509,901],{"class":543},[266,3511,3180],{"class":427},[266,3513,3183],{"class":550},[266,3515,625],{"class":543},[266,3517,3188],{"class":427},[266,3519,3191],{"class":550},[266,3521,675],{"class":543},[266,3523,3180],{"class":427},[266,3525,625],{"class":543},[266,3527,3200],{"class":427},[266,3529,1150],{"class":550},[266,3531,3532],{"class":268,"line":458},[266,3533,446],{"emptyLinePlaceholder":445},[266,3535,3536],{"class":268,"line":463},[266,3537,3538],{"class":272},"    // Loop over rss_feeds and spawn threads\n",[266,3540,3541,3543,3546,3548],{"class":268,"line":481},[266,3542,2189],{"class":543},[266,3544,3545],{"class":550}," (key, value) ",[266,3547,1076],{"class":543},[266,3549,1079],{"class":550},[266,3551,3552,3554,3556,3558,3560,3562,3564,3566,3568,3570],{"class":268,"line":666},[266,3553,2226],{"class":543},[266,3555,3265],{"class":550},[266,3557,675],{"class":543},[266,3559,3270],{"class":427},[266,3561,625],{"class":543},[266,3563,3275],{"class":427},[266,3565,1087],{"class":550},[266,3567,3280],{"class":543},[266,3569,3283],{"class":543},[266,3571,863],{"class":550},[266,3573,3574,3576,3578,3581],{"class":268,"line":689},[266,3575,1084],{"class":427},[266,3577,1087],{"class":550},[266,3579,3580],{"class":431},"\"{}\"",[266,3582,3583],{"class":550},", key);\n",[266,3585,3586],{"class":268,"line":716},[266,3587,3588],{"class":550},"        });\n",[266,3590,3591],{"class":268,"line":739},[266,3592,930],{"class":550},[266,3594,3595],{"class":268,"line":745},[266,3596,580],{"class":550},[12,3598,3599],{},[302,3600],{"alt":3601,"src":3602},"VS-Code-Terminal, Fehler im Variablenbereich mit Referenzen und Thread-Verschiebungs-Closure","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398627/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/vs_code_terminal_cargo_build_error_function_threads_variable_scopes.png",[12,3604,3605,3606,3609,3610,3612,3613,3615,3616,415],{},"Obwohl die Variable ",[239,3607,3608],{},"key"," im Funktionsbereich erstellt wurde, verweist sie auf die Variable ",[239,3611,591],{}," und kann nicht in den Thread-Bereich verschoben werden. Werte, auf die über den Funktionsparameter ",[239,3614,591],{}," zugegriffen wird, erfordern eine lokale Kopie mit ",[239,3617,3618],{},"clone()",[12,3620,3621],{},[302,3622],{"alt":3623,"src":3624},"VS-Code-Terminal, Thread-Spawn mit Klon","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398624/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_rust_thread_spawn_clone.png",[257,3626,3628],{"className":259,"code":3627,"language":261,"meta":262,"style":262},"pub fn get_feeds(rss_feeds: &HashMap\u003CString, String>) {\n\n    // Store threads in vector\n    let mut threads: Vec\u003Cthread::JoinHandle\u003C()>> = Vec::new();\n\n    // Loop over rss_feeds and spawn threads\n    for (name, url) in rss_feeds {\n        let thread_name = name.clone();\n        let thread_url = url.clone();\n        let thread = thread::spawn(move || {\n            // Use thread_name and thread_url as values, see next chapter for instructions.\n",[239,3629,3630,3656,3660,3664,3694,3698,3702,3712,3728,3744,3766],{"__ignoreMap":262},[266,3631,3632,3634,3636,3638,3640,3642,3644,3646,3648,3650,3652,3654],{"class":268,"line":269},[266,3633,854],{"class":543},[266,3635,892],{"class":543},[266,3637,895],{"class":427},[266,3639,898],{"class":550},[266,3641,901],{"class":543},[266,3643,904],{"class":543},[266,3645,532],{"class":427},[266,3647,909],{"class":550},[266,3649,912],{"class":427},[266,3651,915],{"class":550},[266,3653,912],{"class":427},[266,3655,920],{"class":550},[266,3657,3658],{"class":268,"line":276},[266,3659,446],{"emptyLinePlaceholder":445},[266,3661,3662],{"class":268,"line":285},[266,3663,3499],{"class":272},[266,3665,3666,3668,3670,3672,3674,3676,3678,3680,3682,3684,3686,3688,3690,3692],{"class":268,"line":449},[266,3667,669],{"class":543},[266,3669,2116],{"class":543},[266,3671,3175],{"class":550},[266,3673,901],{"class":543},[266,3675,3180],{"class":427},[266,3677,3183],{"class":550},[266,3679,625],{"class":543},[266,3681,3188],{"class":427},[266,3683,3191],{"class":550},[266,3685,675],{"class":543},[266,3687,3180],{"class":427},[266,3689,625],{"class":543},[266,3691,3200],{"class":427},[266,3693,1150],{"class":550},[266,3695,3696],{"class":268,"line":458},[266,3697,446],{"emptyLinePlaceholder":445},[266,3699,3700],{"class":268,"line":463},[266,3701,3538],{"class":272},[266,3703,3704,3706,3708,3710],{"class":268,"line":481},[266,3705,2189],{"class":543},[266,3707,1073],{"class":550},[266,3709,1076],{"class":543},[266,3711,1079],{"class":550},[266,3713,3714,3716,3718,3720,3722,3724,3726],{"class":268,"line":666},[266,3715,2226],{"class":543},[266,3717,3228],{"class":550},[266,3719,675],{"class":543},[266,3721,3233],{"class":550},[266,3723,415],{"class":543},[266,3725,3238],{"class":427},[266,3727,1150],{"class":550},[266,3729,3730,3732,3734,3736,3738,3740,3742],{"class":268,"line":689},[266,3731,2226],{"class":543},[266,3733,3247],{"class":550},[266,3735,675],{"class":543},[266,3737,3252],{"class":550},[266,3739,415],{"class":543},[266,3741,3238],{"class":427},[266,3743,1150],{"class":550},[266,3745,3746,3748,3750,3752,3754,3756,3758,3760,3762,3764],{"class":268,"line":716},[266,3747,2226],{"class":543},[266,3749,3265],{"class":550},[266,3751,675],{"class":543},[266,3753,3270],{"class":427},[266,3755,625],{"class":543},[266,3757,3275],{"class":427},[266,3759,1087],{"class":550},[266,3761,3280],{"class":543},[266,3763,3283],{"class":543},[266,3765,863],{"class":550},[266,3767,3768],{"class":268,"line":739},[266,3769,3770],{"class":272},"            // Use thread_name and thread_url as values, see next chapter for instructions.\n",[214,3772,3774],{"id":3773},"feed-xml-in-objekttypen-parsen","Feed-XML in Objekttypen parsen",[12,3776,3777],{},"Als Nächstes werden die Schritte für das Parsen des RSS-Feeds im Thread-Closure wiederholt. Füge folgende Codekommentare hinzu:",[354,3779,3780,3789],{},[39,3781,3782,3785,3786,415],{},[239,3783,3784],{},"// Parse XML body with feed_rs parser, input in bytes",". Damit rufst du den Inhalt der RSS-Feed-URL ab und parst ihn mit den Crate-Funktionen ",[239,3787,3788],{},"feed_rs",[39,3790,3791,3794,3795,3798,3799,3806],{},[239,3792,3793],{},"// Check feed_type attribute feed_rs::model::FeedType::RSS2 or Atom and print its name",": Extrahiere den Feed-Typ, indem du das Attribut ",[239,3796,3797],{},"feed_type"," mit dem ",[16,3800,3803],{"href":3801,"rel":3802},"https://docs.rs/feed-rs/latest/feed_rs/model/enum.FeedType.html",[],[239,3804,3805],{},"feed_rs::model::FeedType"," vergleichst. Dazu braucht Codevorschläge Anweisungen, in denen die genauen ENUM-Werte für den Abgleich angegeben werden.",[12,3808,3809],{},[302,3810],{"alt":3811,"src":3812},"Weise Codevorschläge an, mit bestimmten Feed-Typen abzugleichen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398622/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_feed_rs_type_condition.png",[257,3814,3816],{"className":259,"code":3815,"language":261,"meta":262,"style":262},"            // Parse XML body with feed_rs parser, input in bytes\n            let body = reqwest::blocking::get(thread_url).unwrap().bytes().unwrap();\n            let feed = feed_rs::parser::parse(body.as_ref()).unwrap();\n\n            // Check feed_type attribute feed_rs::model::FeedType::RSS2 or Atom and print its name\n            if feed.feed_type == feed_rs::model::FeedType::RSS2 {\n                println!(\"{} is an RSS2 feed\", thread_name);\n            } else if feed.feed_type == feed_rs::model::FeedType::Atom {\n                println!(\"{} is an Atom feed\", thread_name);\n            }\n",[239,3817,3818,3822,3862,3896,3900,3905,3940,3953,3989,4000],{"__ignoreMap":262},[266,3819,3820],{"class":268,"line":269},[266,3821,1937],{"class":272},[266,3823,3824,3826,3828,3830,3832,3834,3836,3838,3840,3843,3845,3847,3849,3851,3854,3856,3858,3860],{"class":268,"line":276},[266,3825,1107],{"class":543},[266,3827,1110],{"class":550},[266,3829,675],{"class":543},[266,3831,1115],{"class":427},[266,3833,625],{"class":543},[266,3835,1120],{"class":427},[266,3837,625],{"class":543},[266,3839,1125],{"class":427},[266,3841,3842],{"class":550},"(thread_url)",[266,3844,415],{"class":543},[266,3846,1133],{"class":427},[266,3848,1136],{"class":550},[266,3850,415],{"class":543},[266,3852,3853],{"class":427},"bytes",[266,3855,1136],{"class":550},[266,3857,415],{"class":543},[266,3859,1133],{"class":427},[266,3861,1150],{"class":550},[266,3863,3864,3866,3869,3871,3873,3875,3877,3879,3881,3883,3885,3888,3890,3892,3894],{"class":268,"line":285},[266,3865,1107],{"class":543},[266,3867,3868],{"class":550}," feed ",[266,3870,675],{"class":543},[266,3872,1948],{"class":427},[266,3874,625],{"class":543},[266,3876,1953],{"class":427},[266,3878,625],{"class":543},[266,3880,1183],{"class":427},[266,3882,1960],{"class":550},[266,3884,415],{"class":543},[266,3886,3887],{"class":427},"as_ref",[266,3889,1968],{"class":550},[266,3891,415],{"class":543},[266,3893,1133],{"class":427},[266,3895,1150],{"class":550},[266,3897,3898],{"class":268,"line":449},[266,3899,446],{"emptyLinePlaceholder":445},[266,3901,3902],{"class":268,"line":458},[266,3903,3904],{"class":272},"            // Check feed_type attribute feed_rs::model::FeedType::RSS2 or Atom and print its name\n",[266,3906,3907,3910,3913,3915,3918,3921,3923,3925,3928,3930,3933,3935,3938],{"class":268,"line":463},[266,3908,3909],{"class":543},"            if",[266,3911,3912],{"class":550}," feed",[266,3914,415],{"class":543},[266,3916,3917],{"class":550},"feed_type ",[266,3919,3920],{"class":543},"==",[266,3922,1948],{"class":427},[266,3924,625],{"class":543},[266,3926,3927],{"class":427},"model",[266,3929,625],{"class":543},[266,3931,3932],{"class":427},"FeedType",[266,3934,625],{"class":543},[266,3936,3937],{"class":437},"RSS2",[266,3939,863],{"class":550},[266,3941,3942,3945,3947,3950],{"class":268,"line":481},[266,3943,3944],{"class":427},"                println!",[266,3946,1087],{"class":550},[266,3948,3949],{"class":431},"\"{} is an RSS2 feed\"",[266,3951,3952],{"class":550},", thread_name);\n",[266,3954,3955,3958,3961,3964,3966,3968,3970,3972,3974,3976,3978,3980,3982,3984,3987],{"class":268,"line":666},[266,3956,3957],{"class":550},"            } ",[266,3959,3960],{"class":543},"else",[266,3962,3963],{"class":543}," if",[266,3965,3912],{"class":550},[266,3967,415],{"class":543},[266,3969,3917],{"class":550},[266,3971,3920],{"class":543},[266,3973,1948],{"class":427},[266,3975,625],{"class":543},[266,3977,3927],{"class":427},[266,3979,625],{"class":543},[266,3981,3932],{"class":427},[266,3983,625],{"class":543},[266,3985,3986],{"class":427},"Atom",[266,3988,863],{"class":550},[266,3990,3991,3993,3995,3998],{"class":268,"line":689},[266,3992,3944],{"class":427},[266,3994,1087],{"class":550},[266,3996,3997],{"class":431},"\"{} is an Atom feed\"",[266,3999,3952],{"class":550},[266,4001,4002],{"class":268,"line":716},[266,4003,4004],{"class":550},"            }\n",[12,4006,4007],{},"Erstelle das Programm und führe es erneut aus. Überprüfe die Ausgabe.",[257,4009,4012],{"className":4010,"code":4011,"language":1141,"meta":262},[1338],"time cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n\nCNCF is an RSS2 feed\nTechCrunch is an RSS2 feed\nGitLab Blog is an Atom feed\nHacker News is an RSS2 feed\n",[239,4013,4011],{"__ignoreMap":262},[12,4015,4016],{},"Wir überprüfen diese Ausgabe: Öffne die Feed-URLs im Browser oder sieh die heruntergeladenen Dateien an.",[12,4018,4019,4020,4023],{},"Hacker News unterstützt RSS-Version 2.0 mit ",[239,4021,4022],{},"channel(title,link,description,item(title,link,pubDate,comments))",". TechCrunch und der CNCF-Blog haben eine ähnliche Struktur.",[257,4025,4029],{"className":4026,"code":4027,"language":4028,"meta":262,"style":262},"language-xml shiki shiki-themes github-light","\u003Crss version=\"2.0\">\u003Cchannel>\u003Ctitle>Hacker News\u003C/title>\u003Clink>https://news.ycombinator.com/\u003C/link>\u003Cdescription>Links for the intellectually curious, ranked by readers.\u003C/description>\u003Citem>\u003Ctitle>Writing a debugger from scratch: Breakpoints\u003C/title>\u003Clink>https://www.timdbg.com/posts/writing-a-debugger-from-scratch-part-5/\u003C/link>\u003CpubDate>Wed, 27 Sep 2023 06:31:25 +0000\u003C/pubDate>\u003Ccomments>https://news.ycombinator.com/item?id=37670938\u003C/comments>\u003Cdescription>\u003C![CDATA[\u003Ca href=\"https://news.ycombinator.com/item?id=37670938\">Comments\u003C/a>]]>\u003C/description>\u003C/item>\u003Citem>\n","xml",[239,4030,4031],{"__ignoreMap":262},[266,4032,4033,4035,4039,4041,4043,4046,4049,4052,4054,4057,4060,4062,4064,4067,4070,4072,4074,4077,4080,4082,4084,4087,4089,4091,4094,4096,4098,4100,4103,4105,4107,4110,4113,4115,4117,4120,4123,4125,4127,4129,4132,4135,4138,4140,4143,4145,4147,4149],{"class":268,"line":269},[266,4034,909],{"class":550},[266,4036,4038],{"class":4037},"shJU0","rss",[266,4040,1777],{"class":427},[266,4042,675],{"class":550},[266,4044,4045],{"class":431},"\"2.0\"",[266,4047,4048],{"class":550},">\u003C",[266,4050,4051],{"class":4037},"channel",[266,4053,4048],{"class":550},[266,4055,4056],{"class":4037},"title",[266,4058,4059],{"class":550},">Hacker News\u003C/",[266,4061,4056],{"class":4037},[266,4063,4048],{"class":550},[266,4065,4066],{"class":4037},"link",[266,4068,4069],{"class":550},">https://news.ycombinator.com/\u003C/",[266,4071,4066],{"class":4037},[266,4073,4048],{"class":550},[266,4075,4076],{"class":4037},"description",[266,4078,4079],{"class":550},">Links for the intellectually curious, ranked by readers.\u003C/",[266,4081,4076],{"class":4037},[266,4083,4048],{"class":550},[266,4085,4086],{"class":4037},"item",[266,4088,4048],{"class":550},[266,4090,4056],{"class":4037},[266,4092,4093],{"class":550},">Writing a debugger from scratch: Breakpoints\u003C/",[266,4095,4056],{"class":4037},[266,4097,4048],{"class":550},[266,4099,4066],{"class":4037},[266,4101,4102],{"class":550},">https://www.timdbg.com/posts/writing-a-debugger-from-scratch-part-5/\u003C/",[266,4104,4066],{"class":4037},[266,4106,4048],{"class":550},[266,4108,4109],{"class":4037},"pubDate",[266,4111,4112],{"class":550},">Wed, 27 Sep 2023 06:31:25 +0000\u003C/",[266,4114,4109],{"class":4037},[266,4116,4048],{"class":550},[266,4118,4119],{"class":4037},"comments",[266,4121,4122],{"class":550},">https://news.ycombinator.com/item?id=37670938\u003C/",[266,4124,4119],{"class":4037},[266,4126,4048],{"class":550},[266,4128,4076],{"class":4037},[266,4130,4131],{"class":550},">",[266,4133,4134],{"class":431},"\u003C![CDATA[\u003Ca href=\"https://news.ycombinator.com/item?id=37670938\">Comments\u003C/a>]]>",[266,4136,4137],{"class":550},"\u003C/",[266,4139,4076],{"class":4037},[266,4141,4142],{"class":550},">\u003C/",[266,4144,4086],{"class":4037},[266,4146,4048],{"class":550},[266,4148,4086],{"class":4037},[266,4150,4151],{"class":550},">\n",[12,4153,4154,4155,4159],{},"Im GitLab-Blog wird das ",[16,4156,3986],{"href":4157,"rel":4158},"https://datatracker.ietf.org/doc/html/rfc4287",[],"-Feed-Format verwendet, das RSS zwar ähnlich ist, aber eine andere Parsing-Logik erfordert.",[257,4161,4163],{"className":4026,"code":4162,"language":4028,"meta":262,"style":262},"\u003C?xml version='1.0' encoding='utf-8' ?>\n\u003Cfeed xmlns='http://www.w3.org/2005/Atom'>\n\u003C!-- / Get release posts -->\n\u003C!-- / Get blog posts -->\n\u003Ctitle>GitLab\u003C/title>\n\u003Cid>https://about.gitlab.com/blog\u003C/id>\n\u003Clink href='https://about.gitlab.com/blog/' />\n\u003Cupdated>2023-09-26T00:00:00+00:00\u003C/updated>\n\u003Cauthor>\n\u003Cname>The GitLab Team\u003C/name>\n\u003C/author>\n\u003Centry>\n\u003Ctitle>Atlassian Server ending: Goodbye disjointed toolchain, hello DevSecOps platform\u003C/title>\n\u003Clink href='https://about.gitlab.com/blog/atlassian-server-ending-move-to-a-single-devsecops-platform/' rel='alternate' />\n\u003Cid>https://about.gitlab.com/blog/atlassian-server-ending-move-to-a-single-devsecops-platform/\u003C/id>\n\u003Cpublished>2023-09-26T00:00:00+00:00\u003C/published>\n\u003Cupdated>2023-09-26T00:00:00+00:00\u003C/updated>\n\u003Cauthor>\n\u003Cname>Dave Steer, Justin Farris\u003C/name>\n\u003C/author>\n",[239,4164,4165,4190,4207,4212,4217,4230,4244,4261,4275,4284,4298,4306,4315,4328,4351,4364,4377,4389,4397,4410],{"__ignoreMap":262},[266,4166,4167,4170,4172,4174,4176,4179,4182,4184,4187],{"class":268,"line":269},[266,4168,4169],{"class":550},"\u003C?",[266,4171,4028],{"class":4037},[266,4173,1777],{"class":427},[266,4175,675],{"class":550},[266,4177,4178],{"class":431},"'1.0'",[266,4180,4181],{"class":427}," encoding",[266,4183,675],{"class":550},[266,4185,4186],{"class":431},"'utf-8'",[266,4188,4189],{"class":550}," ?>\n",[266,4191,4192,4194,4197,4200,4202,4205],{"class":268,"line":276},[266,4193,909],{"class":550},[266,4195,4196],{"class":4037},"feed",[266,4198,4199],{"class":427}," xmlns",[266,4201,675],{"class":550},[266,4203,4204],{"class":431},"'http://www.w3.org/2005/Atom'",[266,4206,4151],{"class":550},[266,4208,4209],{"class":268,"line":285},[266,4210,4211],{"class":272},"\u003C!-- / Get release posts -->\n",[266,4213,4214],{"class":268,"line":449},[266,4215,4216],{"class":272},"\u003C!-- / Get blog posts -->\n",[266,4218,4219,4221,4223,4226,4228],{"class":268,"line":458},[266,4220,909],{"class":550},[266,4222,4056],{"class":4037},[266,4224,4225],{"class":550},">GitLab\u003C/",[266,4227,4056],{"class":4037},[266,4229,4151],{"class":550},[266,4231,4232,4234,4237,4240,4242],{"class":268,"line":463},[266,4233,909],{"class":550},[266,4235,4236],{"class":4037},"id",[266,4238,4239],{"class":550},">https://about.gitlab.com/blog\u003C/",[266,4241,4236],{"class":4037},[266,4243,4151],{"class":550},[266,4245,4246,4248,4250,4253,4255,4258],{"class":268,"line":481},[266,4247,909],{"class":550},[266,4249,4066],{"class":4037},[266,4251,4252],{"class":427}," href",[266,4254,675],{"class":550},[266,4256,4257],{"class":431},"'https://about.gitlab.com/blog/'",[266,4259,4260],{"class":550}," />\n",[266,4262,4263,4265,4268,4271,4273],{"class":268,"line":666},[266,4264,909],{"class":550},[266,4266,4267],{"class":4037},"updated",[266,4269,4270],{"class":550},">2023-09-26T00:00:00+00:00\u003C/",[266,4272,4267],{"class":4037},[266,4274,4151],{"class":550},[266,4276,4277,4279,4282],{"class":268,"line":689},[266,4278,909],{"class":550},[266,4280,4281],{"class":4037},"author",[266,4283,4151],{"class":550},[266,4285,4286,4288,4291,4294,4296],{"class":268,"line":716},[266,4287,909],{"class":550},[266,4289,4290],{"class":4037},"name",[266,4292,4293],{"class":550},">The GitLab Team\u003C/",[266,4295,4290],{"class":4037},[266,4297,4151],{"class":550},[266,4299,4300,4302,4304],{"class":268,"line":739},[266,4301,4137],{"class":550},[266,4303,4281],{"class":4037},[266,4305,4151],{"class":550},[266,4307,4308,4310,4313],{"class":268,"line":745},[266,4309,909],{"class":550},[266,4311,4312],{"class":4037},"entry",[266,4314,4151],{"class":550},[266,4316,4317,4319,4321,4324,4326],{"class":268,"line":750},[266,4318,909],{"class":550},[266,4320,4056],{"class":4037},[266,4322,4323],{"class":550},">Atlassian Server ending: Goodbye disjointed toolchain, hello DevSecOps platform\u003C/",[266,4325,4056],{"class":4037},[266,4327,4151],{"class":550},[266,4329,4330,4332,4334,4336,4338,4341,4344,4346,4349],{"class":268,"line":1157},[266,4331,909],{"class":550},[266,4333,4066],{"class":4037},[266,4335,4252],{"class":427},[266,4337,675],{"class":550},[266,4339,4340],{"class":431},"'https://about.gitlab.com/blog/atlassian-server-ending-move-to-a-single-devsecops-platform/'",[266,4342,4343],{"class":427}," rel",[266,4345,675],{"class":550},[266,4347,4348],{"class":431},"'alternate'",[266,4350,4260],{"class":550},[266,4352,4353,4355,4357,4360,4362],{"class":268,"line":1163},[266,4354,909],{"class":550},[266,4356,4236],{"class":4037},[266,4358,4359],{"class":550},">https://about.gitlab.com/blog/atlassian-server-ending-move-to-a-single-devsecops-platform/\u003C/",[266,4361,4236],{"class":4037},[266,4363,4151],{"class":550},[266,4365,4366,4368,4371,4373,4375],{"class":268,"line":1200},[266,4367,909],{"class":550},[266,4369,4370],{"class":4037},"published",[266,4372,4270],{"class":550},[266,4374,4370],{"class":4037},[266,4376,4151],{"class":550},[266,4378,4379,4381,4383,4385,4387],{"class":268,"line":1205},[266,4380,909],{"class":550},[266,4382,4267],{"class":4037},[266,4384,4270],{"class":550},[266,4386,4267],{"class":4037},[266,4388,4151],{"class":550},[266,4390,4391,4393,4395],{"class":268,"line":1211},[266,4392,909],{"class":550},[266,4394,4281],{"class":4037},[266,4396,4151],{"class":550},[266,4398,4399,4401,4403,4406,4408],{"class":268,"line":1224},[266,4400,909],{"class":550},[266,4402,4290],{"class":4037},[266,4404,4405],{"class":550},">Dave Steer, Justin Farris\u003C/",[266,4407,4290],{"class":4037},[266,4409,4151],{"class":550},[266,4411,4412,4414,4416],{"class":268,"line":1230},[266,4413,4137],{"class":550},[266,4415,4281],{"class":4037},[266,4417,4151],{"class":550},[232,4419,166],{"id":4420},"generische-feed-datentypen-zuordnen",[12,4422,4423,4424,4431,4432,4437,4438,4440],{},"Mit ",[16,4425,4428],{"href":4426,"rel":4427},"https://docs.rs/roxmltree/latest/roxmltree/struct.Document.html",[],[239,4429,4430],{},"roxmltree::Document::parse"," müssten wir den XML-Knotenbaum und dessen spezifische Tag-Namen verstehen. Glücklicherweise bietet ",[16,4433,4436],{"href":4434,"rel":4435},"https://docs.rs/feed-rs/latest/feed_rs/model/struct.Feed.html",[],"feed_rs::model::Feed"," ein kombiniertes Modell für RSS- und Atom-Feeds. Wir verwenden daher die Crate ",[239,4439,3788],{}," weiter.",[354,4442,4443,4446],{},[39,4444,4445],{},"Atom: Feed->Feed, Eintrag->Eintrag",[39,4447,4448],{},"RSS: Kanal->Feed, Element->Eintrag",[12,4450,4451,4452,4457,4458,4460],{},"Zusätzlich zur obigen Zuordnung müssen wir die erforderlichen Attribute extrahieren und deren Datentypen zuordnen. Es ist hilfreich, ",[16,4453,4456],{"href":4454,"rel":4455},"https://docs.rs/feed-rs/latest/feed_rs/model/index.html",[],"die Dokumentation für feed_rs::model"," zu öffnen, um die Strukturen und ihre Felder sowie Implementierungen zu verstehen. Andernfalls würden einige Vorschläge zu Fehlern bei der Typkonvertierung und Kompilierungsfehlern führen, die für die Implementierung von ",[239,4459,3788],{}," spezifisch sind.",[12,4462,4463,4464,4470,4471,4473,4474,4477,4478,4485],{},"Eine ",[16,4465,4467],{"href":4434,"rel":4466},[],[239,4468,4469],{},"Feed","-Struktur liefert den ",[239,4472,4056],{},", Typ ",[239,4475,4476],{},"Option\u003CText>"," (entweder ist ein Wert festgelegt oder nichts). Eine ",[16,4479,4482],{"href":4480,"rel":4481},"https://docs.rs/feed-rs/latest/feed_rs/model/struct.Entry.html",[],[239,4483,4484],{},"Entry","-Struktur bietet:",[354,4487,4488,4508,4531,4548],{},[39,4489,4490,1727,4492,4494,4495,4501,4502,4505,4506,415],{},[239,4491,4056],{},[239,4493,4476],{},"mit ",[16,4496,4499],{"href":4497,"rel":4498},"https://docs.rs/feed-rs/latest/feed_rs/model/struct.Text.html",[],[239,4500,1264],{}," und dem Feld ",[239,4503,4504],{},"content"," als ",[239,4507,912],{},[39,4509,4510,1727,4512,2448,4515,4522,4523,415],{},[239,4511,4267],{},[239,4513,4514],{},"Option\u003CDateTime\u003CUtc>>",[16,4516,4519],{"href":4517,"rel":4518},"https://docs.rs/chrono/latest/chrono/struct.DateTime.html",[],[239,4520,4521],{},"DateTime"," mit der ",[16,4524,4527,4530],{"href":4525,"rel":4526},"https://docs.rs/chrono/latest/chrono/struct.DateTime.html#method.format",[],[239,4528,4529],{},"format()","-Methode",[39,4532,4533,1727,4536,1921,4538,4543,4544,4505,4546,415],{},[239,4534,4535],{},"summary",[239,4537,4476],{},[16,4539,4541],{"href":4497,"rel":4540},[],[239,4542,1264],{}," und das Feld ",[239,4545,4504],{},[239,4547,912],{},[39,4549,4550,1727,4553,4556,4557,4564,4565,4568],{},[239,4551,4552],{},"links",[239,4554,4555],{},"Vec\u003CLink>",", Vektor mit ",[16,4558,4561],{"href":4559,"rel":4560},"https://docs.rs/feed-rs/latest/feed_rs/model/struct.Link.html",[],[239,4562,4563],{},"Link","-Elementen. Das Attribut ",[239,4566,4567],{},"href"," liefert die rohe URL-Zeichenfolge.",[12,4570,4571,4572,4574,4575,4577],{},"Nutze dieses Wissen, um die erforderlichen Daten aus den Feed-Einträgen zu extrahieren. Zur Erinnerung: Alle ",[239,4573,1260],{},"-Typen müssen ",[239,4576,1247],{}," aufrufen und erfordert weitere rohe Anweisungen für Codevorschläge.",[257,4579,4581],{"className":259,"code":4580,"language":261,"meta":262,"style":262},"                // https://docs.rs/feed-rs/latest/feed_rs/model/struct.Feed.html\n                // https://docs.rs/feed-rs/latest/feed_rs/model/struct.Entry.html\n                // Loop over all entries, and print\n                // title.unwrap().content\n                // published.unwrap().format\n                // summary.unwrap().content\n                // links href as joined string\n                for entry in feed.entries {\n                    println!(\"Title: {}\", entry.title.unwrap().content);\n                    println!(\"Published: {}\", entry.published.unwrap().format(\"%Y-%m-%d %H:%M:%S\"));\n                    println!(\"Summary: {}\", entry.summary.unwrap().content);\n                    println!(\"Links: {:?}\", entry.links.iter().map(|link| link.href.clone()).collect::\u003CVec\u003CString>>().join(\", \"));\n                    println!();\n                }\n",[239,4582,4583,4588,4593,4598,4603,4608,4613,4618,4635,4663,4695,4720,4799,4805],{"__ignoreMap":262},[266,4584,4585],{"class":268,"line":269},[266,4586,4587],{"class":272},"                // https://docs.rs/feed-rs/latest/feed_rs/model/struct.Feed.html\n",[266,4589,4590],{"class":268,"line":276},[266,4591,4592],{"class":272},"                // https://docs.rs/feed-rs/latest/feed_rs/model/struct.Entry.html\n",[266,4594,4595],{"class":268,"line":285},[266,4596,4597],{"class":272},"                // Loop over all entries, and print\n",[266,4599,4600],{"class":268,"line":449},[266,4601,4602],{"class":272},"                // title.unwrap().content\n",[266,4604,4605],{"class":268,"line":458},[266,4606,4607],{"class":272},"                // published.unwrap().format\n",[266,4609,4610],{"class":268,"line":463},[266,4611,4612],{"class":272},"                // summary.unwrap().content\n",[266,4614,4615],{"class":268,"line":481},[266,4616,4617],{"class":272},"                // links href as joined string\n",[266,4619,4620,4623,4626,4628,4630,4632],{"class":268,"line":666},[266,4621,4622],{"class":543},"                for",[266,4624,4625],{"class":550}," entry ",[266,4627,1076],{"class":543},[266,4629,3912],{"class":550},[266,4631,415],{"class":543},[266,4633,4634],{"class":550},"entries {\n",[266,4636,4637,4640,4642,4645,4648,4650,4652,4654,4656,4658,4660],{"class":268,"line":689},[266,4638,4639],{"class":427},"                    println!",[266,4641,1087],{"class":550},[266,4643,4644],{"class":431},"\"Title: {}\"",[266,4646,4647],{"class":550},", entry",[266,4649,415],{"class":543},[266,4651,4056],{"class":550},[266,4653,415],{"class":543},[266,4655,1133],{"class":427},[266,4657,1136],{"class":550},[266,4659,415],{"class":543},[266,4661,4662],{"class":550},"content);\n",[266,4664,4665,4667,4669,4672,4674,4676,4678,4680,4682,4684,4686,4688,4690,4693],{"class":268,"line":716},[266,4666,4639],{"class":427},[266,4668,1087],{"class":550},[266,4670,4671],{"class":431},"\"Published: {}\"",[266,4673,4647],{"class":550},[266,4675,415],{"class":543},[266,4677,4370],{"class":550},[266,4679,415],{"class":543},[266,4681,1133],{"class":427},[266,4683,1136],{"class":550},[266,4685,415],{"class":543},[266,4687,2845],{"class":427},[266,4689,1087],{"class":550},[266,4691,4692],{"class":431},"\"%Y-%m-%d %H:%M:%S\"",[266,4694,2853],{"class":550},[266,4696,4697,4699,4701,4704,4706,4708,4710,4712,4714,4716,4718],{"class":268,"line":739},[266,4698,4639],{"class":427},[266,4700,1087],{"class":550},[266,4702,4703],{"class":431},"\"Summary: {}\"",[266,4705,4647],{"class":550},[266,4707,415],{"class":543},[266,4709,4535],{"class":550},[266,4711,415],{"class":543},[266,4713,1133],{"class":427},[266,4715,1136],{"class":550},[266,4717,415],{"class":543},[266,4719,4662],{"class":550},[266,4721,4722,4724,4726,4729,4731,4733,4735,4737,4740,4742,4744,4747,4749,4752,4754,4756,4759,4761,4763,4765,4767,4769,4771,4774,4776,4778,4781,4783,4785,4788,4790,4792,4794,4797],{"class":268,"line":745},[266,4723,4639],{"class":427},[266,4725,1087],{"class":550},[266,4727,4728],{"class":431},"\"Links: {:?}\"",[266,4730,4647],{"class":550},[266,4732,415],{"class":543},[266,4734,4552],{"class":550},[266,4736,415],{"class":543},[266,4738,4739],{"class":427},"iter",[266,4741,1136],{"class":550},[266,4743,415],{"class":543},[266,4745,4746],{"class":427},"map",[266,4748,1087],{"class":550},[266,4750,4751],{"class":543},"|",[266,4753,4066],{"class":550},[266,4755,4751],{"class":543},[266,4757,4758],{"class":550}," link",[266,4760,415],{"class":543},[266,4762,4567],{"class":550},[266,4764,415],{"class":543},[266,4766,3238],{"class":427},[266,4768,1968],{"class":550},[266,4770,415],{"class":543},[266,4772,4773],{"class":427},"collect",[266,4775,625],{"class":543},[266,4777,909],{"class":550},[266,4779,4780],{"class":427},"Vec",[266,4782,909],{"class":550},[266,4784,912],{"class":427},[266,4786,4787],{"class":550},">>()",[266,4789,415],{"class":543},[266,4791,3341],{"class":427},[266,4793,1087],{"class":550},[266,4795,4796],{"class":431},"\", \"",[266,4798,2853],{"class":550},[266,4800,4801,4803],{"class":268,"line":750},[266,4802,4639],{"class":427},[266,4804,1150],{"class":550},[266,4806,4807],{"class":268,"line":1157},[266,4808,4809],{"class":550},"                }\n",[12,4811,4812],{},[302,4813],{"alt":4814,"src":4815},"Codevorschläge zum Drucken von Feed-Eintragstypen mit spezifischen Anforderungen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398622/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_print_feed_entries_fields_with_rust_type_specifics.png",[232,4817,4819],{"id":4818},"fehlerbehandlung-mit-der-option-unwrap","Fehlerbehandlung mit der Option unwrap()",[12,4821,4822,4823,4825,4826,4829,4830,4832],{},"Wiederhole die mehrzeiligen Anweisungen, nachdem du das Programm erstellt und erneut ausgeführt hast. Spoiler: ",[239,4824,1247],{}," ruft das Makro ",[239,4827,4828],{},"panic!"," auf und lässt das Programm abstürzen, wenn es auf leere Werte stößt. Dies kann passieren, wenn ein Feld wie ",[239,4831,4535],{}," in den Feed-Daten nicht festgelegt ist.",[257,4834,4836],{"className":418,"code":4835,"language":420,"meta":262,"style":262},"GitLab Blog is an Atom feed\nTitle: How the Colmena project uses GitLab to support citizen journalists\nPublished: 2023-09-27 00:00:00\nthread '\u003Cunnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/feed_reader.rs:40:59\n",[239,4837,4838,4858,4893,4904],{"__ignoreMap":262},[266,4839,4840,4843,4846,4849,4852,4855],{"class":268,"line":269},[266,4841,4842],{"class":427},"GitLab",[266,4844,4845],{"class":431}," Blog",[266,4847,4848],{"class":431}," is",[266,4850,4851],{"class":431}," an",[266,4853,4854],{"class":431}," Atom",[266,4856,4857],{"class":431}," feed\n",[266,4859,4860,4863,4866,4869,4872,4875,4878,4881,4884,4887,4890],{"class":268,"line":276},[266,4861,4862],{"class":427},"Title:",[266,4864,4865],{"class":431}," How",[266,4867,4868],{"class":431}," the",[266,4870,4871],{"class":431}," Colmena",[266,4873,4874],{"class":431}," project",[266,4876,4877],{"class":431}," uses",[266,4879,4880],{"class":431}," GitLab",[266,4882,4883],{"class":431}," to",[266,4885,4886],{"class":431}," support",[266,4888,4889],{"class":431}," citizen",[266,4891,4892],{"class":431}," journalists\n",[266,4894,4895,4898,4901],{"class":268,"line":285},[266,4896,4897],{"class":427},"Published:",[266,4899,4900],{"class":431}," 2023-09-27",[266,4902,4903],{"class":431}," 00:00:00\n",[266,4905,4906,4908,4911,4914,4917,4920],{"class":268,"line":449},[266,4907,3083],{"class":427},[266,4909,4910],{"class":431}," '\u003Cunnamed>'",[266,4912,4913],{"class":431}," panicked",[266,4915,4916],{"class":431}," at",[266,4918,4919],{"class":431}," 'called `Option::unwrap()` on a `None` value',",[266,4921,4922],{"class":431}," src/feed_reader.rs:40:59\n",[12,4924,4925,4926,4933,4934,4936],{},"Mögliche Lösung: ",[16,4927,4930],{"href":4928,"rel":4929},"https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or_else",[],[239,4931,4932],{},"std::Option::unwrap_or_else"," verwenden und einen leeren String als Standardwert festlegen. Die Syntax erfordert einen Closure, der eine leere ",[239,4935,1264],{},"-Strukturinstanziierung zurückgibt.",[12,4938,4939],{},"Es waren viele Versuche nötig, um die richtige Initialisierung zu finden. Das Übergeben nur einer leeren Zeichenfolge funktionierte nicht mit benutzerdefinierten Typen. Ich zeige dir, was ich versucht habe.",[257,4941,4943],{"className":259,"code":4942,"language":261,"meta":262,"style":262},"// Problem: The `summary` attribute is not always initialized. unwrap() will panic! then.\n// Requires use mime; and use feed_rs::model::Text;\n/*\n// 1st attempt: Use unwrap() to extraxt Text from Option\u003CText> type.\nprintln!(\"Summary: {}\", entry.summary.unwrap().content);\n// 2nd attempt. Learned about unwrap_or_else, passing an empty string.\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| \"\").content);\n// 3rd attempt. summary is of the Text type, pass a new struct instantiation.\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{}).content);\n// 4th attempt. Struct instantiation requires 3 field values.\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{\"\", \"\", \"\"}).content);\n// 5th attempt. Struct instantation with public fields requires key: value syntax\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: \"\", src: \"\", content: \"\"}).content);\n// 6th attempt. Reviewed expected Text types in https://docs.rs/feed-rs/latest/feed_rs/model/struct.Text.html and created Mime and String objects\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: String::new(), content: String::new()}).content);\n// 7th attempt: String and Option\u003CString> cannot be casted automagically. Compiler suggested using `Option::Some()`.\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: Option::Some(), content: String::new()}).content);\n*/\n\n// xth attempt: Solution. Option::Some() requires a new String object.\nprintln!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: Option::Some(String::new()), content: String::new()}).content);\n",[239,4944,4945,4950,4955,4960,4965,4970,4975,4980,4985,4990,4995,5000,5005,5010,5015,5020,5025,5030,5035,5039,5044],{"__ignoreMap":262},[266,4946,4947],{"class":268,"line":269},[266,4948,4949],{"class":272},"// Problem: The `summary` attribute is not always initialized. unwrap() will panic! then.\n",[266,4951,4952],{"class":268,"line":276},[266,4953,4954],{"class":272},"// Requires use mime; and use feed_rs::model::Text;\n",[266,4956,4957],{"class":268,"line":285},[266,4958,4959],{"class":272},"/*\n",[266,4961,4962],{"class":268,"line":449},[266,4963,4964],{"class":272},"// 1st attempt: Use unwrap() to extraxt Text from Option\u003CText> type.\n",[266,4966,4967],{"class":268,"line":458},[266,4968,4969],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap().content);\n",[266,4971,4972],{"class":268,"line":463},[266,4973,4974],{"class":272},"// 2nd attempt. Learned about unwrap_or_else, passing an empty string.\n",[266,4976,4977],{"class":268,"line":481},[266,4978,4979],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| \"\").content);\n",[266,4981,4982],{"class":268,"line":666},[266,4983,4984],{"class":272},"// 3rd attempt. summary is of the Text type, pass a new struct instantiation.\n",[266,4986,4987],{"class":268,"line":689},[266,4988,4989],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{}).content);\n",[266,4991,4992],{"class":268,"line":716},[266,4993,4994],{"class":272},"// 4th attempt. Struct instantiation requires 3 field values.\n",[266,4996,4997],{"class":268,"line":739},[266,4998,4999],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{\"\", \"\", \"\"}).content);\n",[266,5001,5002],{"class":268,"line":745},[266,5003,5004],{"class":272},"// 5th attempt. Struct instantation with public fields requires key: value syntax\n",[266,5006,5007],{"class":268,"line":750},[266,5008,5009],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: \"\", src: \"\", content: \"\"}).content);\n",[266,5011,5012],{"class":268,"line":1157},[266,5013,5014],{"class":272},"// 6th attempt. Reviewed expected Text types in https://docs.rs/feed-rs/latest/feed_rs/model/struct.Text.html and created Mime and String objects\n",[266,5016,5017],{"class":268,"line":1163},[266,5018,5019],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: String::new(), content: String::new()}).content);\n",[266,5021,5022],{"class":268,"line":1200},[266,5023,5024],{"class":272},"// 7th attempt: String and Option\u003CString> cannot be casted automagically. Compiler suggested using `Option::Some()`.\n",[266,5026,5027],{"class":268,"line":1205},[266,5028,5029],{"class":272},"println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: Option::Some(), content: String::new()}).content);\n",[266,5031,5032],{"class":268,"line":1211},[266,5033,5034],{"class":272},"*/\n",[266,5036,5037],{"class":268,"line":1224},[266,5038,446],{"emptyLinePlaceholder":445},[266,5040,5041],{"class":268,"line":1230},[266,5042,5043],{"class":272},"// xth attempt: Solution. Option::Some() requires a new String object.\n",[266,5045,5046,5049,5051,5053,5055,5057,5059,5061,5064,5066,5068,5071,5074,5076,5079,5081,5084,5087,5089,5092,5094,5097,5099,5101,5103,5105,5108,5110,5113,5115,5117,5120,5122],{"class":268,"line":1235},[266,5047,5048],{"class":427},"println!",[266,5050,1087],{"class":550},[266,5052,4703],{"class":431},[266,5054,4647],{"class":550},[266,5056,415],{"class":543},[266,5058,4535],{"class":550},[266,5060,415],{"class":543},[266,5062,5063],{"class":427},"unwrap_or_else",[266,5065,1087],{"class":550},[266,5067,3438],{"class":543},[266,5069,5070],{"class":427}," Text",[266,5072,5073],{"class":550},"{content_type",[266,5075,901],{"class":543},[266,5077,5078],{"class":427}," mime",[266,5080,625],{"class":543},[266,5082,5083],{"class":437},"TEXT_PLAIN",[266,5085,5086],{"class":550},", src",[266,5088,901],{"class":543},[266,5090,5091],{"class":427}," Option",[266,5093,625],{"class":543},[266,5095,5096],{"class":427},"Some",[266,5098,1087],{"class":550},[266,5100,912],{"class":427},[266,5102,625],{"class":543},[266,5104,3200],{"class":427},[266,5106,5107],{"class":550},"()), content",[266,5109,901],{"class":543},[266,5111,5112],{"class":427}," String",[266,5114,625],{"class":543},[266,5116,3200],{"class":427},[266,5118,5119],{"class":550},"()})",[266,5121,415],{"class":543},[266,5123,4662],{"class":550},[12,5125,5126,5127,1921,5129,5132,5133,5135],{},"Dies war nicht zufriedenstellend, da die Codezeile kompliziert ist und manuelle Arbeit ohne Codevorschläge erforderte. Ich ging also einen Schritt zurück: Wenn ",[239,5128,1260],{},[239,5130,5131],{},"none"," ist, gibt ",[239,5134,1247],{}," einen Fehler  aus. Ich fragte Codevorschläge in einem neuen Kommentar:",[257,5137,5140],{"className":5138,"code":5139,"language":1141,"meta":262},[1338],"                // xth attempt: Solution. Option::Some() requires a new String object.\n                println!(\"Summary: {}\", entry.summary.unwrap_or_else(|| Text{content_type: mime::TEXT_PLAIN, src: Option::Some(String::new()), content: String::new()}).content);\n\n                // Alternatively, use Option.is_none()\n",[239,5141,5139],{"__ignoreMap":262},[12,5143,5144],{},[302,5145],{"alt":5146,"src":5147},"Codevorschläge hat nach Alternativen gefragt, wenn Options.is_none","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398608/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/code_suggestions_after_complex_unwrap_or_else_ask_for_alternative_option.png",[12,5149,5150,5151,5153],{},"Ergebnis: erhöhte Lesbarkeit, weniger CPU-Zyklen, die mit ",[239,5152,1247],{}," verschwendet wurden, und eine Lernkurve .",[12,5155,5156],{},"Denke daran: Füge das Speichern der XML-Daten auf der Festplatte erneut hinzu, um die Reader-App erneut abzuschließen.",[257,5158,5160],{"className":259,"code":5159,"language":261,"meta":262,"style":262},"                // Dump the parsed body to a file, as name-current-iso-date.xml\n                let file_name = format!(\"{}-{}.xml\", thread_name, chrono::Local::now().format(\"%Y-%m-%d-%H-%M-%S\"));\n                let mut file = std::fs::File::create(file_name).unwrap();\n                file.write_all(body.as_ref()).unwrap();\n",[239,5161,5162,5167,5210,5243],{"__ignoreMap":262},[266,5163,5164],{"class":268,"line":269},[266,5165,5166],{"class":272},"                // Dump the parsed body to a file, as name-current-iso-date.xml\n",[266,5168,5169,5172,5175,5177,5179,5181,5183,5186,5189,5191,5193,5195,5197,5199,5201,5203,5205,5208],{"class":268,"line":276},[266,5170,5171],{"class":543},"                let",[266,5173,5174],{"class":550}," file_name ",[266,5176,675],{"class":543},[266,5178,2832],{"class":427},[266,5180,1087],{"class":550},[266,5182,2837],{"class":431},[266,5184,5185],{"class":550},", thread_name, ",[266,5187,5188],{"class":427},"chrono",[266,5190,625],{"class":543},[266,5192,2813],{"class":427},[266,5194,625],{"class":543},[266,5196,2818],{"class":427},[266,5198,1136],{"class":550},[266,5200,415],{"class":543},[266,5202,2845],{"class":427},[266,5204,1087],{"class":550},[266,5206,5207],{"class":431},"\"%Y-%m-%d-%H-%M-%S\"",[266,5209,2853],{"class":550},[266,5211,5212,5214,5216,5218,5220,5222,5224,5226,5228,5230,5232,5234,5237,5239,5241],{"class":268,"line":285},[266,5213,5171],{"class":543},[266,5215,2116],{"class":543},[266,5217,2862],{"class":550},[266,5219,675],{"class":543},[266,5221,622],{"class":427},[266,5223,625],{"class":543},[266,5225,2871],{"class":427},[266,5227,625],{"class":543},[266,5229,2876],{"class":427},[266,5231,625],{"class":543},[266,5233,2881],{"class":427},[266,5235,5236],{"class":550},"(file_name)",[266,5238,415],{"class":543},[266,5240,1133],{"class":427},[266,5242,1150],{"class":550},[266,5244,5245,5248,5250,5252,5254,5256,5258,5260,5262,5264],{"class":268,"line":449},[266,5246,5247],{"class":550},"                file",[266,5249,415],{"class":543},[266,5251,2900],{"class":427},[266,5253,1960],{"class":550},[266,5255,415],{"class":543},[266,5257,3887],{"class":427},[266,5259,1968],{"class":550},[266,5261,415],{"class":543},[266,5263,1133],{"class":427},[266,5265,1150],{"class":550},[12,5267,5268],{},"Erstelle das Programm, führe es aus, um die Ausgabe zu überprüfen.",[257,5270,5272],{"className":418,"code":5271,"language":420,"meta":262,"style":262},"cargo build\n\ntime cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n",[239,5273,5274,5280,5284],{"__ignoreMap":262},[266,5275,5276,5278],{"class":268,"line":269},[266,5277,452],{"class":427},[266,5279,1708],{"class":431},[266,5281,5282],{"class":268,"line":276},[266,5283,446],{"emptyLinePlaceholder":445},[266,5285,5286,5288,5291,5294],{"class":268,"line":285},[266,5287,2978],{"class":543},[266,5289,5290],{"class":550}," cargo run -- ",[266,5292,5293],{"class":431},"\"GitLab Blog,https://about.gitlab.com/atom.xml\"",[266,5295,2413],{"class":431},[12,5297,5298],{},[302,5299],{"alt":5300,"src":374},"VS-Code-Terminal, cargo run mit formatierter Ausgabe von Feed-Einträgen",[214,5302,178],{"id":5303},"benchmarks",[232,5305,5307],{"id":5306},"benchmarks-für-sequentielle-vs-parallele-ausführung","Benchmarks für sequentielle vs. parallele Ausführung",[12,5309,5310],{},"Vergleiche die Ausführungszeit-Benchmarks, indem du jeweils fünf Samples erstellst.",[354,5312,5313,5321],{},[39,5314,5315,5316],{},"Sequentielle Ausführung. ",[16,5317,5320],{"href":5318,"rel":5319},"https://gitlab.com/gitlab-da/use-cases/ai/learn-with-ai/learn-rust-ai-app-reader/-/merge_requests/1",[],"Beispiel-Quellcode MR",[39,5322,5323,5324],{},"Parallele Ausführung. ",[16,5325,5320],{"href":5326,"rel":5327},"https://gitlab.com/gitlab-da/use-cases/ai/learn-with-ai/learn-rust-ai-app-reader/-/merge_requests/3",[],[257,5329,5331],{"className":418,"code":5330,"language":420,"meta":262,"style":262},"# Sequential\ngit checkout sequential-exec\n\ntime cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n\n0.21s user 0.08s system 10% cpu 2.898 total\n0.21s user 0.08s system 11% cpu 2.585 total\n0.21s user 0.09s system 10% cpu 2.946 total\n0.19s user 0.08s system 10% cpu 2.714 total\n0.20s user 0.10s system 10% cpu 2.808 total\n",[239,5332,5333,5338,5346,5350,5360,5364,5390,5410,5430,5450],{"__ignoreMap":262},[266,5334,5335],{"class":268,"line":269},[266,5336,5337],{"class":272},"# Sequential\n",[266,5339,5340,5342,5344],{"class":268,"line":276},[266,5341,466],{"class":427},[266,5343,3017],{"class":431},[266,5345,3023],{"class":431},[266,5347,5348],{"class":268,"line":285},[266,5349,446],{"emptyLinePlaceholder":445},[266,5351,5352,5354,5356,5358],{"class":268,"line":449},[266,5353,2978],{"class":543},[266,5355,5290],{"class":550},[266,5357,5293],{"class":431},[266,5359,2413],{"class":431},[266,5361,5362],{"class":268,"line":458},[266,5363,446],{"emptyLinePlaceholder":445},[266,5365,5366,5369,5372,5375,5378,5381,5384,5387],{"class":268,"line":463},[266,5367,5368],{"class":427},"0.21s",[266,5370,5371],{"class":431}," user",[266,5373,5374],{"class":431}," 0.08s",[266,5376,5377],{"class":431}," system",[266,5379,5380],{"class":431}," 10%",[266,5382,5383],{"class":431}," cpu",[266,5385,5386],{"class":437}," 2.898",[266,5388,5389],{"class":431}," total\n",[266,5391,5392,5394,5396,5398,5400,5403,5405,5408],{"class":268,"line":481},[266,5393,5368],{"class":427},[266,5395,5371],{"class":431},[266,5397,5374],{"class":431},[266,5399,5377],{"class":431},[266,5401,5402],{"class":431}," 11%",[266,5404,5383],{"class":431},[266,5406,5407],{"class":437}," 2.585",[266,5409,5389],{"class":431},[266,5411,5412,5414,5416,5419,5421,5423,5425,5428],{"class":268,"line":666},[266,5413,5368],{"class":427},[266,5415,5371],{"class":431},[266,5417,5418],{"class":431}," 0.09s",[266,5420,5377],{"class":431},[266,5422,5380],{"class":431},[266,5424,5383],{"class":431},[266,5426,5427],{"class":437}," 2.946",[266,5429,5389],{"class":431},[266,5431,5432,5435,5437,5439,5441,5443,5445,5448],{"class":268,"line":689},[266,5433,5434],{"class":427},"0.19s",[266,5436,5371],{"class":431},[266,5438,5374],{"class":431},[266,5440,5377],{"class":431},[266,5442,5380],{"class":431},[266,5444,5383],{"class":431},[266,5446,5447],{"class":437}," 2.714",[266,5449,5389],{"class":431},[266,5451,5452,5455,5457,5460,5462,5464,5466,5469],{"class":268,"line":716},[266,5453,5454],{"class":427},"0.20s",[266,5456,5371],{"class":431},[266,5458,5459],{"class":431}," 0.10s",[266,5461,5377],{"class":431},[266,5463,5380],{"class":431},[266,5465,5383],{"class":431},[266,5467,5468],{"class":437}," 2.808",[266,5470,5389],{"class":431},[257,5472,5474],{"className":418,"code":5473,"language":420,"meta":262,"style":262},"# Parallel\ngit checkout parallel-exec\n\ntime cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n\n0.19s user 0.08s system 17% cpu 1.515 total\n0.18s user 0.08s system 16% cpu 1.561 total\n0.18s user 0.07s system 17% cpu 1.414 total\n0.19s user 0.08s system 18% cpu 1.447 total\n0.17s user 0.08s system 16% cpu 1.453 total\n",[239,5475,5476,5481,5490,5494,5504,5508,5528,5549,5569,5589],{"__ignoreMap":262},[266,5477,5478],{"class":268,"line":269},[266,5479,5480],{"class":272},"# Parallel\n",[266,5482,5483,5485,5487],{"class":268,"line":276},[266,5484,466],{"class":427},[266,5486,3017],{"class":431},[266,5488,5489],{"class":431}," parallel-exec\n",[266,5491,5492],{"class":268,"line":285},[266,5493,446],{"emptyLinePlaceholder":445},[266,5495,5496,5498,5500,5502],{"class":268,"line":449},[266,5497,2978],{"class":543},[266,5499,5290],{"class":550},[266,5501,5293],{"class":431},[266,5503,2413],{"class":431},[266,5505,5506],{"class":268,"line":458},[266,5507,446],{"emptyLinePlaceholder":445},[266,5509,5510,5512,5514,5516,5518,5521,5523,5526],{"class":268,"line":463},[266,5511,5434],{"class":427},[266,5513,5371],{"class":431},[266,5515,5374],{"class":431},[266,5517,5377],{"class":431},[266,5519,5520],{"class":431}," 17%",[266,5522,5383],{"class":431},[266,5524,5525],{"class":437}," 1.515",[266,5527,5389],{"class":431},[266,5529,5530,5533,5535,5537,5539,5542,5544,5547],{"class":268,"line":481},[266,5531,5532],{"class":427},"0.18s",[266,5534,5371],{"class":431},[266,5536,5374],{"class":431},[266,5538,5377],{"class":431},[266,5540,5541],{"class":431}," 16%",[266,5543,5383],{"class":431},[266,5545,5546],{"class":437}," 1.561",[266,5548,5389],{"class":431},[266,5550,5551,5553,5555,5558,5560,5562,5564,5567],{"class":268,"line":666},[266,5552,5532],{"class":427},[266,5554,5371],{"class":431},[266,5556,5557],{"class":431}," 0.07s",[266,5559,5377],{"class":431},[266,5561,5520],{"class":431},[266,5563,5383],{"class":431},[266,5565,5566],{"class":437}," 1.414",[266,5568,5389],{"class":431},[266,5570,5571,5573,5575,5577,5579,5582,5584,5587],{"class":268,"line":689},[266,5572,5434],{"class":427},[266,5574,5371],{"class":431},[266,5576,5374],{"class":431},[266,5578,5377],{"class":431},[266,5580,5581],{"class":431}," 18%",[266,5583,5383],{"class":431},[266,5585,5586],{"class":437}," 1.447",[266,5588,5389],{"class":431},[266,5590,5591,5594,5596,5598,5600,5602,5604,5607],{"class":268,"line":716},[266,5592,5593],{"class":427},"0.17s",[266,5595,5371],{"class":431},[266,5597,5374],{"class":431},[266,5599,5377],{"class":431},[266,5601,5541],{"class":431},[266,5603,5383],{"class":431},[266,5605,5606],{"class":437}," 1.453",[266,5608,5389],{"class":431},[12,5610,5611],{},"Die CPU-Nutzung ist bei der parallelen Ausführung von vier RSS-Feed-Threads gestiegen, hat aber die Gesamtzeit fast halbiert. Wenn wir dies beachten, können wir unsere Kenntnisse von Rust vertiefen und den Code und die Funktionalität optimieren.",[12,5613,5614],{},"Beachte, dass wir den Debug-Build über Cargo ausführen und noch nicht über die optimierten veröffentlichten Builds. Einschränkungen bei der parallelen Ausführung: Einige HTTP-Endpunkte haben Ratenbegrenzungen eingeführt.",[12,5616,5617,5618,5623],{},"Das System, das mehrere Threads parallel ausführt, könnte ebenfalls überlastet werden – Threads erfordern einen Kontextwechsel im Kernel und weisen jedem Thread Ressourcen zu. Während ein Thread Rechenressourcen erhält, werden andere Threads in den Ruhezustand versetzt. Wenn zu viele Threads gespawned werden, kann dies das System verlangsamen, anstatt den Vorgang zu beschleunigen. Lösungen umfassen Entwurfsmuster wie ",[16,5619,5622],{"href":5620,"rel":5621},"https://docs.rs/work-queue/latest/work_queue/",[],"Arbeitswarteschlangen",", bei denen der Caller eine Aufgabe in eine Warteschlange einfügt und eine definierte Anzahl von Worker-Threads die Aufgaben für die asynchrone Ausführung aufnimmt.",[12,5625,5626,5627,5632,5633,5638],{},"Rust bietet auch eine Datensynchronisation zwischen Threads, sogenannten ",[16,5628,5631],{"href":5629,"rel":5630},"https://doc.rust-lang.org/rust-by-example/std_misc/channels.html",[],"Channels",". Um einen gleichzeitigen Datenzugriff zu gewährleisten, stehen ",[16,5634,5637],{"href":5635,"rel":5636},"https://doc.rust-lang.org/std/sync/struct.Mutex.html",[],"mutexes"," zur Verfügung, die sichere Sperren bieten.",[232,5640,192],{"id":5641},"cicd-mit-rust-caching",[12,5643,5644,5645,5648,5649,5652,5653,5655],{},"Füge die folgende CI/CD-Konfiguration in die Datei ",[239,5646,5647],{},".gitlab-ci.yml"," ein. Der Job ",[239,5650,5651],{},"run-latest"," ruft ",[239,5654,1834],{}," mit URL-Beispielen für RSS-Feeds auf und misst die Ausführungszeit kontinuierlich.",[257,5657,5660],{"className":5658,"code":5659,"language":1141,"meta":262},[1338],"stages:\n  - build\n  - test\n  - run\n\ndefault:\n  image: rust:latest\n  cache:\n    key: ${CI_COMMIT_REF_SLUG}\n    paths:\n      - .cargo/bin\n      - .cargo/registry/index\n      - .cargo/registry/cache\n      - target/debug/deps\n      - target/debug/build\n    policy: pull-push\n\n# Cargo data needs to be in the project directory for being cached.\nvariables:\n  CARGO_HOME:${CI_PROJECT_DIR}/.cargo\n\nbuild-latest:\n  stage: build\n  script:\n    - cargo build --verbose\n\ntest-latest:\n  stage: build\n  script:\n    - cargo test --verbose\n\nrun-latest:\n  stage: run\n  script:\n    - time cargo run -- \"GitLab Blog,https://about.gitlab.com/atom.xml\" \"CNCF,https://www.cncf.io/feed/\"\n",[239,5661,5659],{"__ignoreMap":262},[12,5663,5664],{},[302,5665],{"alt":5666,"src":5667},"GitLab-CI/CD-Pipelines für Rust, Cargo-Run-Ausgabe","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398626/blog/Content%20Images/learn-rust-with-ai-code-suggestions-advanced-programming/gitlab_cicd_pipeline_rust_cargo_run_output.png",[214,5669,198],{"id":5670},"wie-geht-es-weiter",[12,5672,5673,5674,5677],{},"Dieser Blogbeitrag war schwierig zu erstellen, da ich sowohl selbst fortgeschrittene Rust-Programmiertechniken erlernte als auch eine gute Lernkurve mit Codevorschlägen fand. Letzteres hilft bei der schnellen Generierung von Code, nicht nur von Textbausteinen. Nach dem Lesen dieses Blogbeitrags kennst du einige Herausforderungen und Turnarounds. Der Beispiel-Lösungscode für die Reader-App ist im Projekt ",[16,5675,397],{"href":408,"rel":5676},[]," verfügbar.",[12,5679,5680,5681,5684,5685,5691],{},"Das Parsen von RSS-Feeds ist herausfordernd, da es sich um Datenstrukturen mit externen HTTP-Anforderungen und parallelen Optimierungen handelt. Als erfahrene(r) Rust-Benutzer(in) hast du dich vielleicht gefragt: ",[239,5682,5683],{},"Warum verwendet er nicht die Crate std::rss?"," -- Sie ist für die erweiterte asynchrone Ausführung optimiert und erlaubt es nicht, die verschiedenen Rust-Funktionen, die in diesem Blogbeitrag erläutert werden, zu zeigen und zu erklären. Versuche als Übung den Code mit der ",[16,5686,1295,5689],{"href":5687,"rel":5688},"https://docs.rs/rss/latest/rss/",[],[239,5690,4038],{}," neu zu schreiben.",[232,5693,206],{"id":5694},"asynchrone-lernübungen",[12,5696,5697],{},"Was du in diesem Blogbeitrag gelernt hast, bildet die Grundlage für zukünftige Projekte mit persistenter Speicherung und Präsentation der Daten. Hier sind ein paar Ideen, mit denen du deine Kenntnisse von Rust vertiefen und die Reader-App optimieren kannst:",[354,5699,5700,5703,5706,5709,5712,5715],{},[39,5701,5702],{},"Datenspeicherung: Verwende eine Datenbank wie sqlite und RSS-Feed-Update-Tracking.",[39,5704,5705],{},"Benachrichtigungen: Spawne untergeordnete Prozesse, um Benachrichtigungen in Telegram usw. auszulösen.",[39,5707,5708],{},"Funktionalität: Erweitere die Reader-Typen zu REST-APIs",[39,5710,5711],{},"Konfiguration: Füge Unterstützung für Konfigurationsdateien für RSS-Feeds, APIs usw. hinzu.",[39,5713,5714],{},"Effizienz: Füge Unterstützung für Filter und abonnierte Tags hinzu.",[39,5716,5717],{},"Bereitstellungen: Verwende einen Webserver, sammle Prometheus-Metriken und stelle auf Kubernetes bereit.",[12,5719,5720,5721,5723],{},"In einem zukünftigen Blogbeitrag werden wir einige dieser Ideen besprechen und zeigen, wie wir sie umsetzen können. Tauche in vorhandene RSS-Feed-Implementierungen ein und erfahre, wie du den vorhandenen Code in Rust-Bibliotheken (",[239,5722,1847],{},") nutzen kannst.",[232,5725,212],{"id":5726},"teile-dein-feedback",[12,5728,5729,5730,5733,5734,415],{},"Wenn du ",[16,5731,5732],{"href":24},"GitLab Duo"," Codevorschläge verwendest, ",[16,5735,5738],{"href":5736,"rel":5737},"https://gitlab.com/gitlab-org/gitlab/-/issues/405152",[],"teile deine Meinung im Feedback-Ticket",[5740,5741,5742],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":262,"searchDepth":276,"depth":276,"links":5744},[5745,5748,5753,5756,5759,5762,5763,5768,5772,5776],{"id":216,"depth":276,"text":217,"children":5746},[5747],{"id":234,"depth":285,"text":52},{"id":308,"depth":276,"text":58,"children":5749},[5750,5751,5752],{"id":332,"depth":285,"text":66},{"id":380,"depth":285,"text":72},{"id":515,"depth":285,"text":78},{"id":783,"depth":276,"text":84,"children":5754},[5755],{"id":1308,"depth":285,"text":1309},{"id":1847,"depth":276,"text":98,"children":5757},[5758],{"id":1903,"depth":285,"text":106},{"id":1997,"depth":276,"text":112,"children":5760},[5761],{"id":2422,"depth":285,"text":2423},{"id":2717,"depth":276,"text":126},{"id":2951,"depth":276,"text":132,"children":5764},[5765,5766,5767],{"id":2960,"depth":285,"text":140},{"id":3051,"depth":285,"text":146},{"id":3409,"depth":285,"text":3410},{"id":3773,"depth":276,"text":3774,"children":5769},[5770,5771],{"id":4420,"depth":285,"text":166},{"id":4818,"depth":285,"text":4819},{"id":5303,"depth":276,"text":178,"children":5773},[5774,5775],{"id":5306,"depth":285,"text":5307},{"id":5641,"depth":285,"text":192},{"id":5670,"depth":276,"text":198,"children":5777},[5778,5779],{"id":5694,"depth":285,"text":206},{"id":5726,"depth":285,"text":212},"ai","2023-10-12","In diesem Tutorial vertiefst du mithilfe der KI-basierten Codevorschläge von GitLab Duo deine Kenntnisse in der fortgeschrittenen Rust-Programmierung.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662439/Blog/Hero%20Images/codewithheart.png",{},"/de-de/blog/learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions",{"title":5,"description":5782,"ogTitle":5,"ogDescription":5782,"noIndex":5785,"ogImage":5786,"ogUrl":5790,"ogSiteName":5791,"ogType":5792,"canonicalUrls":5790},"https://about.gitlab.com/blog/learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions","https://about.gitlab.com","article","learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions","de-de/blog/learn-advanced-rust-programming-with-a-little-help-from-ai-code-suggestions",[5796,5797,5798,5799,5800],"DevSecOps","careers","tutorial","workflow","AI","BlogPost","2025-01-29","i0YX_sHiqVQkPm_GcN4NqIn6-KId6LBvzyywotogKlU",{"logo":5805,"freeTrial":5810,"sales":5815,"login":5820,"items":5825,"search":6154,"minimal":6188,"duo":6206,"switchNav":6215,"pricingDeployment":6226},{"config":5806},{"href":5807,"dataGaName":5808,"dataGaLocation":5809},"/de-de/","gitlab logo","header",{"text":5811,"config":5812},"Kostenlose Testversion anfordern",{"href":5813,"dataGaName":5814,"dataGaLocation":5809},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de&glm_content=default-saas-trial/","free trial",{"text":5816,"config":5817},"Demo anfordern",{"href":5818,"dataGaName":5819,"dataGaLocation":5809},"/de-de/sales/?contact-topic=request-demo","sales",{"text":5821,"config":5822},"Anmelden",{"href":5823,"dataGaName":5824,"dataGaLocation":5809},"https://gitlab.com/users/sign_in/","sign in",[5826,5855,5957,5962,6076,6132],{"text":5827,"config":5828,"menu":5830},"Plattform",{"dataNavLevelOne":5829},"platform",{"type":5831,"columns":5832},"cards",[5833,5839,5847],{"title":5827,"description":5834,"link":5835},"Die intelligente Orchestrierungsplattform für DevSecOps",{"text":5836,"config":5837},"Die Plattform erkunden",{"href":5838,"dataGaName":5829,"dataGaLocation":5809},"/de-de/platform/",{"title":5840,"description":5841,"link":5842},"GitLab Duo Agent Platform","Agentische KI für den gesamten Software-Lebenszyklus",{"text":5843,"config":5844},"Lerne GitLab Duo kennen",{"href":5845,"dataGaName":5846,"dataGaLocation":5809},"/de-de/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":5848,"description":5849,"link":5850},"Warum GitLab?","Erfahre, warum sich Unternehmen für GitLab entscheiden",{"text":5851,"config":5852},"Mehr erfahren",{"href":5853,"dataGaName":5854,"dataGaLocation":5809},"/de-de/why-gitlab/","why gitlab",{"text":5856,"left":445,"config":5857,"menu":5859},"Produkt",{"dataNavLevelOne":5858},"solutions",{"type":5860,"link":5861,"columns":5865,"feature":5936},"lists",{"text":5862,"config":5863},"Alle Lösungen anzeigen",{"href":5864,"dataGaName":5858,"dataGaLocation":5809},"/de-de/solutions/",[5866,5891,5914],{"title":5867,"description":5868,"link":5869,"items":5874},"Automatisierung","CI/CD und Automatisierung zur Beschleunigung der Bereitstellung",{"config":5870},{"icon":5871,"href":5872,"dataGaName":5873,"dataGaLocation":5809},"AutomatedCodeAlt","/de-de/solutions/delivery-automation/","automated software delivery",[5875,5879,5882,5887],{"text":5876,"config":5877},"CI/CD",{"href":5878,"dataGaLocation":5809,"dataGaName":5876},"/de-de/solutions/continuous-integration/",{"text":5840,"config":5880},{"href":5845,"dataGaLocation":5809,"dataGaName":5881},"gitlab duo agent platform - product menu",{"text":5883,"config":5884},"Quellcodeverwaltung",{"href":5885,"dataGaLocation":5809,"dataGaName":5886},"/de-de/solutions/source-code-management/","Source Code Management",{"text":5888,"config":5889},"Automatische Softwarebereitstellung",{"href":5872,"dataGaLocation":5809,"dataGaName":5890},"Automated software delivery",{"title":5892,"description":5893,"link":5894,"items":5899},"Sicherheit","Entwickle Code schneller ohne Abstriche bei der Sicherheit",{"config":5895},{"href":5896,"dataGaName":5897,"dataGaLocation":5809,"icon":5898},"/de-de/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[5900,5904,5909],{"text":5901,"config":5902},"Anwendungssicherheitstests",{"href":5896,"dataGaName":5903,"dataGaLocation":5809},"Application security testing",{"text":5905,"config":5906},"Schutz der Software-Lieferkette",{"href":5907,"dataGaLocation":5809,"dataGaName":5908},"/de-de/solutions/supply-chain/","Software supply chain security",{"text":5910,"config":5911},"Software-Compliance",{"href":5912,"dataGaName":5913,"dataGaLocation":5809},"/de-de/solutions/software-compliance/","software compliance",{"title":5915,"link":5916,"items":5921},"Messung",{"config":5917},{"icon":5918,"href":5919,"dataGaName":5920,"dataGaLocation":5809},"DigitalTransformation","/de-de/solutions/visibility-measurement/","visibility and measurement",[5922,5926,5931],{"text":5923,"config":5924},"Sichtbarkeit und Messung",{"href":5919,"dataGaLocation":5809,"dataGaName":5925},"Visibility and Measurement",{"text":5927,"config":5928},"Wertstrommanagement",{"href":5929,"dataGaLocation":5809,"dataGaName":5930},"/de-de/solutions/value-stream-management/","Value Stream Management",{"text":5932,"config":5933},"Analysen und Einblicke",{"href":5934,"dataGaLocation":5809,"dataGaName":5935},"/de-de/solutions/analytics-and-insights/","Analytics and insights",{"title":5937,"type":5860,"items":5938},"GitLab für",[5939,5945,5951],{"text":5940,"config":5941},"Enterprise",{"icon":5942,"href":5943,"dataGaLocation":5809,"dataGaName":5944},"Building","/de-de/enterprise/","enterprise",{"text":5946,"config":5947},"Kleinunternehmen",{"icon":5948,"href":5949,"dataGaLocation":5809,"dataGaName":5950},"Work","/de-de/small-business/","small business",{"text":5952,"config":5953},"Öffentlicher Sektor",{"icon":5954,"href":5955,"dataGaLocation":5809,"dataGaName":5956},"Organization","/de-de/solutions/public-sector/","public sector",{"text":5958,"config":5959},"Preise",{"href":5960,"dataGaName":5961,"dataGaLocation":5809,"dataNavLevelOne":5961},"/de-de/pricing/","pricing",{"text":5963,"config":5964,"menu":5966},"Ressourcen",{"dataNavLevelOne":5965},"resources",{"type":5860,"link":5967,"columns":5971,"feature":6065},{"text":5968,"config":5969},"Alle Ressourcen anzeigen",{"href":5970,"dataGaName":5965,"dataGaLocation":5809},"/de-de/resources/",[5972,6005,6032],{"title":5973,"items":5974},"Erste Schritte",[5975,5980,5985,5990,5995,6000],{"text":5976,"config":5977},"Installieren",{"href":5978,"dataGaName":5979,"dataGaLocation":5809},"/de-de/install/","install",{"text":5981,"config":5982},"Kurzanleitungen",{"href":5983,"dataGaName":5984,"dataGaLocation":5809},"/de-de/get-started/","quick setup checklists",{"text":5986,"config":5987},"Lernen",{"href":5988,"dataGaLocation":5809,"dataGaName":5989},"https://university.gitlab.com/","learn",{"text":5991,"config":5992},"Produktdokumentation",{"href":5993,"dataGaName":5994,"dataGaLocation":5809},"https://docs.gitlab.com/","product documentation",{"text":5996,"config":5997},"Best-Practice-Videos",{"href":5998,"dataGaName":5999,"dataGaLocation":5809},"/de-de/getting-started-videos/","best practice videos",{"text":6001,"config":6002},"Integrationen",{"href":6003,"dataGaName":6004,"dataGaLocation":5809},"/de-de/integrations/","integrations",{"title":6006,"items":6007},"Entdecken",[6008,6013,6018,6023,6027],{"text":6009,"config":6010},"Kundenerfolge",{"href":6011,"dataGaName":6012,"dataGaLocation":5809},"/de-de/customers/","customer success stories",{"text":6014,"config":6015},"Blog",{"href":6016,"dataGaName":6017,"dataGaLocation":5809},"/de-de/blog/","blog",{"text":6019,"config":6020},"Demo-Hub",{"href":6021,"dataGaName":6022,"dataGaLocation":5809},"/de-de/demo-hub/","demo hub",{"text":6024,"config":6025},"The Source",{"href":6026,"dataGaName":6017,"dataGaLocation":5809},"/de-de/the-source/",{"text":6028,"config":6029},"Remote",{"href":6030,"dataGaName":6031,"dataGaLocation":5809},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":6033,"items":6034},"Vernetzen",[6035,6040,6045,6050,6055,6060],{"text":6036,"config":6037},"GitLab-Services",{"href":6038,"dataGaName":6039,"dataGaLocation":5809},"/de-de/services/","services",{"text":6041,"config":6042},"Beitragen",{"href":6043,"dataGaName":6044,"dataGaLocation":5809},"https://contributors.gitlab.com","contribute",{"text":6046,"config":6047},"Community",{"href":6048,"dataGaName":6049,"dataGaLocation":5809},"/community/","community",{"text":6051,"config":6052},"Forum",{"href":6053,"dataGaName":6054,"dataGaLocation":5809},"https://forum.gitlab.com/","forum",{"text":6056,"config":6057},"Veranstaltungen",{"href":6058,"dataGaName":6059,"dataGaLocation":5809},"/events/","events",{"text":6061,"config":6062},"Partner",{"href":6063,"dataGaName":6064,"dataGaLocation":5809},"/de-de/partners/","partners",{"config":6066,"title":6069,"text":6070,"link":6071},{"background":6067,"textColor":6068},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","Neues bei GitLab","Über die neuesten Funktionen und Verbesserungen auf dem Laufenden bleiben.",{"text":6072,"config":6073},"Aktuelle Nachrichten",{"href":6074,"dataGaName":6075,"dataGaLocation":5809},"/de-de/whats-new/","whats new",{"text":6077,"config":6078,"menu":6080},"Unternehmen",{"dataNavLevelOne":6079},"company",{"type":5860,"columns":6081},[6082],{"items":6083},[6084,6089,6095,6097,6102,6107,6112,6117,6122,6127],{"text":6085,"config":6086},"Über",{"href":6087,"dataGaName":6088,"dataGaLocation":5809},"/de-de/company/","about",{"text":6090,"config":6091,"footerGa":6094},"Karriere",{"href":6092,"dataGaName":6093,"dataGaLocation":5809},"/jobs/","jobs",{"dataGaName":6093},{"text":6056,"config":6096},{"href":6058,"dataGaName":6059,"dataGaLocation":5809},{"text":6098,"config":6099},"Geschäftsführung",{"href":6100,"dataGaName":6101,"dataGaLocation":5809},"/company/team/e-group/","leadership",{"text":6103,"config":6104},"Handbuch",{"href":6105,"dataGaName":6106,"dataGaLocation":5809},"https://handbook.gitlab.com/","handbook",{"text":6108,"config":6109},"Investor Relations",{"href":6110,"dataGaName":6111,"dataGaLocation":5809},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":6113,"config":6114},"Trust Center",{"href":6115,"dataGaName":6116,"dataGaLocation":5809},"/de-de/security/","trust center",{"text":6118,"config":6119},"AI Transparency Center",{"href":6120,"dataGaName":6121,"dataGaLocation":5809},"/de-de/ai-transparency-center/","ai transparency center",{"text":6123,"config":6124},"Newsletter",{"href":6125,"dataGaName":6126,"dataGaLocation":5809},"/company/contact/#contact-forms","newsletter",{"text":6128,"config":6129},"Presse",{"href":6130,"dataGaName":6131,"dataGaLocation":5809},"/press/","press",{"text":6133,"config":6134,"menu":6135},"Kontakt",{"dataNavLevelOne":6079},{"type":5860,"columns":6136},[6137],{"items":6138},[6139,6144,6149],{"text":6140,"config":6141},"Vertrieb kontaktieren",{"href":6142,"dataGaName":6143,"dataGaLocation":5809},"/de-de/sales/","talk to sales",{"text":6145,"config":6146},"Support-Portal",{"href":6147,"dataGaName":6148,"dataGaLocation":5809},"https://support.gitlab.com/hc/en-us","support portal",{"text":6150,"config":6151},"Kundenportal",{"href":6152,"dataGaName":6153,"dataGaLocation":5809},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":6155,"login":6156,"suggestions":6163},"Schließen",{"text":6157,"link":6158},"Um Repositorys und Projekte zu durchsuchen, melde dich an bei",{"text":6159,"config":6160},"gitlab.com",{"href":5823,"dataGaName":6161,"dataGaLocation":6162},"search login","search",{"text":6164,"default":6165},"Vorschläge",[6166,6168,6173,6175,6180,6185],{"text":5840,"config":6167},{"href":5845,"dataGaName":5840,"dataGaLocation":6162},{"text":6169,"config":6170},"Codevorschläge (KI)",{"href":6171,"dataGaName":6172,"dataGaLocation":6162},"/de-de/solutions/code-suggestions/","Code Suggestions (AI)",{"text":5876,"config":6174},{"href":5878,"dataGaName":5876,"dataGaLocation":6162},{"text":6176,"config":6177},"GitLab auf AWS",{"href":6178,"dataGaName":6179,"dataGaLocation":6162},"/de-de/partners/technology-partners/aws/","GitLab on AWS",{"text":6181,"config":6182},"GitLab auf Google Cloud",{"href":6183,"dataGaName":6184,"dataGaLocation":6162},"/de-de/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":5848,"config":6186},{"href":5853,"dataGaName":6187,"dataGaLocation":6162},"Why GitLab?",{"freeTrial":6189,"mobileIcon":6194,"desktopIcon":6199,"secondaryButton":6202},{"text":6190,"config":6191},"Kostenlos testen",{"href":6192,"dataGaName":5814,"dataGaLocation":6193},"https://gitlab.com/-/trials/new/","nav",{"altText":6195,"config":6196},"GitLab-Symbol",{"src":6197,"dataGaName":6198,"dataGaLocation":6193},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":6195,"config":6200},{"src":6201,"dataGaName":6198,"dataGaLocation":6193},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":5973,"config":6203},{"href":6204,"dataGaName":6205,"dataGaLocation":6193},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de/get-started/","get started",{"freeTrial":6207,"mobileIcon":6211,"desktopIcon":6213},{"text":6208,"config":6209},"Mehr über GitLab Duo erfahren",{"href":5845,"dataGaName":6210,"dataGaLocation":6193},"gitlab duo",{"altText":6195,"config":6212},{"src":6197,"dataGaName":6198,"dataGaLocation":6193},{"altText":6195,"config":6214},{"src":6201,"dataGaName":6198,"dataGaLocation":6193},{"button":6216,"mobileIcon":6221,"desktopIcon":6223},{"text":6217,"config":6218},"/Option",{"href":6219,"dataGaName":6220,"dataGaLocation":6193},"#contact","switch",{"altText":6195,"config":6222},{"src":6197,"dataGaName":6198,"dataGaLocation":6193},{"altText":6195,"config":6224},{"src":6225,"dataGaName":6198,"dataGaLocation":6193},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":6227,"mobileIcon":6232,"desktopIcon":6234},{"text":6228,"config":6229},"Zurück zur Preisübersicht",{"href":5960,"dataGaName":6230,"dataGaLocation":6193,"icon":6231},"back to pricing","GoBack",{"altText":6195,"config":6233},{"src":6197,"dataGaName":6198,"dataGaLocation":6193},{"altText":6195,"config":6235},{"src":6201,"dataGaName":6198,"dataGaLocation":6193},{"title":6237,"button":6238,"config":6242},"GitLab Orbit ist da: die Kontextebene für KI-Agenten",{"text":5851,"config":6239},{"href":6240,"dataGaName":6241,"dataGaLocation":5809},"/de-de/gitlab-orbit/","orbit",{"layout":6243,"disabled":5785},"release",{"data":6245},{"text":6246,"source":6247,"edit":6253,"contribute":6258,"config":6263,"items":6268,"minimal":6473},"Git ist eine Marke von Software Freedom Conservancy und unsere Verwendung von „GitLab“ erfolgt unter Lizenz.",{"text":6248,"config":6249},"Quelltext der Seite anzeigen",{"href":6250,"dataGaName":6251,"dataGaLocation":6252},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":6254,"config":6255},"Diese Seite bearbeiten",{"href":6256,"dataGaName":6257,"dataGaLocation":6252},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":6259,"config":6260},"Beteilige dich",{"href":6261,"dataGaName":6262,"dataGaLocation":6252},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":6264,"facebook":6265,"youtube":6266,"linkedin":6267},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[6269,6314,6366,6408,6440],{"title":5958,"links":6270,"subMenu":6285},[6271,6275,6280],{"text":6272,"config":6273},"Tarife anzeigen",{"href":5960,"dataGaName":6274,"dataGaLocation":6252},"view plans",{"text":6276,"config":6277},"Vorteile von Premium",{"href":6278,"dataGaName":6279,"dataGaLocation":6252},"/de-de/pricing/premium/","why premium",{"text":6281,"config":6282},"Vorteile von Ultimate",{"href":6283,"dataGaName":6284,"dataGaLocation":6252},"/de-de/pricing/ultimate/","why ultimate",[6286],{"title":6133,"links":6287},[6288,6290,6292,6294,6299,6304,6309],{"text":6140,"config":6289},{"href":6142,"dataGaName":5819,"dataGaLocation":6252},{"text":6145,"config":6291},{"href":6147,"dataGaName":6148,"dataGaLocation":6252},{"text":6150,"config":6293},{"href":6152,"dataGaName":6153,"dataGaLocation":6252},{"text":6295,"config":6296},"Status",{"href":6297,"dataGaName":6298,"dataGaLocation":6252},"https://status.gitlab.com/","status",{"text":6300,"config":6301},"Nutzungsbedingungen",{"href":6302,"dataGaName":6303,"dataGaLocation":6252},"/terms/","terms of use",{"text":6305,"config":6306},"Datenschutzerklärung",{"href":6307,"dataGaName":6308,"dataGaLocation":6252},"/de-de/privacy/","privacy statement",{"text":6310,"config":6311},"Cookie-Einstellungen",{"dataGaName":6312,"dataGaLocation":6252,"id":6313,"isOneTrustButton":445},"cookie preferences","ot-sdk-btn",{"title":5856,"links":6315,"subMenu":6324},[6316,6320],{"text":6317,"config":6318},"DevSecOps-Plattform",{"href":5838,"dataGaName":6319,"dataGaLocation":6252},"devsecops platform",{"text":6321,"config":6322},"KI-unterstützte Entwicklung",{"href":5845,"dataGaName":6323,"dataGaLocation":6252},"ai-assisted development",[6325],{"title":6326,"links":6327},"Themen",[6328,6332,6337,6342,6347,6351,6356,6361],{"text":5876,"config":6329},{"href":6330,"dataGaName":6331,"dataGaLocation":6252},"/de-de/topics/ci-cd/","cicd",{"text":6333,"config":6334},"GitOps",{"href":6335,"dataGaName":6336,"dataGaLocation":6252},"/de-de/topics/gitops/","gitops",{"text":6338,"config":6339},"DevOps",{"href":6340,"dataGaName":6341,"dataGaLocation":6252},"/de-de/topics/devops/","devops",{"text":6343,"config":6344},"Versionskontrolle",{"href":6345,"dataGaName":6346,"dataGaLocation":6252},"/de-de/topics/version-control/","version control",{"text":5796,"config":6348},{"href":6349,"dataGaName":6350,"dataGaLocation":6252},"/de-de/topics/devsecops/","devsecops",{"text":6352,"config":6353},"Cloud-nativ",{"href":6354,"dataGaName":6355,"dataGaLocation":6252},"/de-de/topics/cloud-native/","cloud native",{"text":6357,"config":6358},"KI für das Programmieren",{"href":6359,"dataGaName":6360,"dataGaLocation":6252},"/de-de/topics/devops/ai-for-coding/","ai for coding",{"text":6362,"config":6363},"Agentische KI",{"href":6364,"dataGaName":6365,"dataGaLocation":6252},"/de-de/topics/agentic-ai/","agentic ai",{"title":6367,"links":6368},"Lösungen",[6369,6372,6374,6379,6383,6386,6389,6392,6394,6396,6398,6403],{"text":5901,"config":6370},{"href":5896,"dataGaName":6371,"dataGaLocation":6252},"Application Security Testing",{"text":5888,"config":6373},{"href":5872,"dataGaName":5873,"dataGaLocation":6252},{"text":6375,"config":6376},"Agile Entwicklung",{"href":6377,"dataGaName":6378,"dataGaLocation":6252},"/de-de/solutions/agile-delivery/","agile delivery",{"text":6380,"config":6381},"SCM",{"href":5885,"dataGaName":6382,"dataGaLocation":6252},"source code management",{"text":5876,"config":6384},{"href":5878,"dataGaName":6385,"dataGaLocation":6252},"continuous integration & delivery",{"text":5927,"config":6387},{"href":5929,"dataGaName":6388,"dataGaLocation":6252},"value stream management",{"text":6333,"config":6390},{"href":6391,"dataGaName":6336,"dataGaLocation":6252},"/de-de/solutions/gitops/",{"text":5940,"config":6393},{"href":5943,"dataGaName":5944,"dataGaLocation":6252},{"text":5946,"config":6395},{"href":5949,"dataGaName":5950,"dataGaLocation":6252},{"text":5952,"config":6397},{"href":5955,"dataGaName":5956,"dataGaLocation":6252},{"text":6399,"config":6400},"Bildungswesen",{"href":6401,"dataGaName":6402,"dataGaLocation":6252},"/de-de/solutions/education/","education",{"text":6404,"config":6405},"Finanzdienstleistungen",{"href":6406,"dataGaName":6407,"dataGaLocation":6252},"/de-de/solutions/finance/","financial services",{"title":5963,"links":6409},[6410,6412,6414,6416,6419,6421,6424,6426,6428,6430,6432,6434,6436,6438],{"text":5976,"config":6411},{"href":5978,"dataGaName":5979,"dataGaLocation":6252},{"text":5981,"config":6413},{"href":5983,"dataGaName":5984,"dataGaLocation":6252},{"text":5986,"config":6415},{"href":5988,"dataGaName":5989,"dataGaLocation":6252},{"text":5991,"config":6417},{"href":5993,"dataGaName":6418,"dataGaLocation":6252},"docs",{"text":6014,"config":6420},{"href":6016,"dataGaName":6017,"dataGaLocation":6252},{"text":6422,"config":6423},"Neuerungen",{"href":6074,"dataGaName":6075,"dataGaLocation":6252},{"text":6009,"config":6425},{"href":6011,"dataGaName":6012,"dataGaLocation":6252},{"text":6028,"config":6427},{"href":6030,"dataGaName":6031,"dataGaLocation":6252},{"text":6036,"config":6429},{"href":6038,"dataGaName":6039,"dataGaLocation":6252},{"text":6041,"config":6431},{"href":6043,"dataGaName":6044,"dataGaLocation":6252},{"text":6046,"config":6433},{"href":6048,"dataGaName":6049,"dataGaLocation":6252},{"text":6051,"config":6435},{"href":6053,"dataGaName":6054,"dataGaLocation":6252},{"text":6056,"config":6437},{"href":6058,"dataGaName":6059,"dataGaLocation":6252},{"text":6061,"config":6439},{"href":6063,"dataGaName":6064,"dataGaLocation":6252},{"title":6077,"links":6441},[6442,6444,6446,6448,6450,6452,6457,6462,6464,6466,6468],{"text":6085,"config":6443},{"href":6087,"dataGaName":6079,"dataGaLocation":6252},{"text":6090,"config":6445},{"href":6092,"dataGaName":6093,"dataGaLocation":6252},{"text":6098,"config":6447},{"href":6100,"dataGaName":6101,"dataGaLocation":6252},{"text":6103,"config":6449},{"href":6105,"dataGaName":6106,"dataGaLocation":6252},{"text":6108,"config":6451},{"href":6110,"dataGaName":6111,"dataGaLocation":6252},{"text":6453,"config":6454},"Nachhaltigkeit",{"href":6455,"dataGaName":6456,"dataGaLocation":6252},"/sustainability/","Sustainability",{"text":6458,"config":6459},"Vielfalt, Inklusion und Zugehörigkeit",{"href":6460,"dataGaName":6461,"dataGaLocation":6252},"/de-de/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":6113,"config":6463},{"href":6115,"dataGaName":6116,"dataGaLocation":6252},{"text":6123,"config":6465},{"href":6125,"dataGaName":6126,"dataGaLocation":6252},{"text":6128,"config":6467},{"href":6130,"dataGaName":6131,"dataGaLocation":6252},{"text":6469,"config":6470},"Transparenzerklärung zu moderner Sklaverei",{"href":6471,"dataGaName":6472,"dataGaLocation":6252},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":6474},[6475,6478,6481],{"text":6476,"config":6477},"Terms",{"href":6302,"dataGaName":6303,"dataGaLocation":6252},{"text":6479,"config":6480},"Cookies",{"dataGaName":6312,"dataGaLocation":6252,"id":6313,"isOneTrustButton":445},{"text":6482,"config":6483},"Datenschutz",{"href":6307,"dataGaName":6308,"dataGaLocation":6252},[6485],{"id":6486,"title":7,"body":5784,"config":6487,"content":6489,"description":5784,"extension":6493,"meta":6494,"navigation":445,"path":6495,"seo":6496,"stem":6497,"__hash__":6498},"blogAuthors/en-us/blog/authors/michael-friedrich.yml",{"template":6488},"BlogAuthor",{"name":7,"config":6490},{"headshot":6491,"ctfId":6492},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659879/Blog/Author%20Headshots/dnsmichi-headshot.jpg","dnsmichi","yml",{},"/en-us/blog/authors/michael-friedrich",{},"en-us/blog/authors/michael-friedrich","lJ-nfRIhdG49Arfrxdn1Vv4UppwD51BB13S3HwIswt4",[6500,6508,6516],{"title":6501,"description":6502,"heroImage":6503,"category":5780,"date":6504,"authors":6505,"slug":6507,"externalUrl":5784},"Wie ich einen Demo-Generator mit Duo Agent Platform baute","So sahen Demos nicht immer aus. Ein Rückblick auf ihre Entwicklung, plus ein Tutorial zum Bau einer eigenen Demo und eines eigenen Agenten.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-08-13",[6506],"Itzik Gan Baruch","agentic-click-through-demo",{"title":6509,"description":6510,"heroImage":6511,"category":5780,"date":6512,"authors":6513,"slug":6515,"externalUrl":5784},"Governance für agentische KI, MCPs und KI-Code-Assistenten","KI-Agenten schreiben, pushen und deployen, ohne dass jeder Schritt geprüft wird. Ein praktisches Framework für Zugriff, Berechtigungen und Audit-Trails.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1785337625/ifzlc2hyzaxhzmjgyymh.png","2026-07-31",[6514],"Julie Griffin","govern-agentic-ai-mcps-code-assistants",{"title":6517,"description":6518,"heroImage":6519,"category":5780,"date":6520,"authors":6521,"slug":6523,"externalUrl":5784},"Claude Opus 5 auf GitLab: Reasoning für die anspruchsvollsten Aufgaben","Anthropics Claude Opus 5 ist jetzt auf der GitLab Duo Agent Platform verfügbar und bringt tieferes Reasoning für die anspruchsvollsten Aufgaben.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099203/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2820%29_2bJGC5ZP3WheoqzlLT05C5_1750099203484.png","2026-07-27",[6522],"Brittany Lutz","claude-opus-5-on-gitlab-duo-agent-platform",{"promotions":6525},[6526,6539,6551,6563],{"id":6527,"categories":6528,"header":6529,"text":6530,"button":6531,"image":6536},"ai-modernization",[5780],"Hält KI, was uns versprochen wurde?","Das Quiz dauert maximal 5 Minuten.",{"text":6532,"config":6533},"Ermittle deinen KI-Reifegrad",{"href":6534,"dataGaName":6535,"dataGaLocation":6017},"/de-de/assessments/ai-modernization-assessment/","modernization assessment",{"config":6537},{"src":6538},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":6540,"categories":6541,"header":6543,"text":6530,"button":6544,"image":6548},"devops-modernization",[6542,6350],"product","Verwaltest du Tool-Chaos oder stellst du Innovationen bereit?",{"text":6545,"config":6546},"Ermittle deinen DevOps-Reifegrad",{"href":6547,"dataGaName":6535,"dataGaLocation":6017},"/de-de/assessments/devops-modernization-assessment/",{"config":6549},{"src":6550},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":6552,"categories":6553,"header":6555,"text":6530,"button":6556,"image":6560},"security-modernization",[6554],"security","Tauschst du Schnelligkeit gegen Sicherheit ein?",{"text":6557,"config":6558},"Ermittle deinen Sicherheitsreifegrad",{"href":6559,"dataGaName":6535,"dataGaLocation":6017},"/de-de/assessments/security-modernization-assessment/",{"config":6561},{"src":6562},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":6564,"paths":6565,"header":6568,"text":6569,"button":6570,"image":6575},"github-azure-migration",[6566,6567],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Ist dein Team bereit für den Umzug von GitHub nach Azure?","GitHub stellt bereits auf Azure um. Finde heraus, was das für dich bedeutet.",{"text":6571,"config":6572},"Erfahre, wie GitLab im Vergleich zu GitHub abschneidet",{"href":6573,"dataGaName":6574,"dataGaLocation":6017},"/de-de/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":6576},{"src":6550},{"header":6578,"blurb":6579,"button":6580,"secondaryButton":6585},"Beginne noch heute, schneller zu entwickeln","Entdecke, was dein Team mit der intelligenten Orchestrierungsplattform für DevSecOps erreichen kann.\n",{"text":6581,"config":6582},"Kostenlosen Test starten",{"href":6583,"dataGaName":5814,"dataGaLocation":6584},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/de-de/","feature",{"text":6140,"config":6586},{"href":6142,"dataGaName":5819,"dataGaLocation":6584},1786803739551]