diff --git a/po/da.po b/po/da.po index 4299ec0e..ec4bc57c 100644 --- a/po/da.po +++ b/po/da.po @@ -51,8 +51,8 @@ msgstr "" msgid "Day 1: Morning" msgstr "Dag 1: Formiddag" -#: src/SUMMARY.md:19 src/SUMMARY.md:76 src/SUMMARY.md:130 src/SUMMARY.md:187 -#: src/SUMMARY.md:213 src/SUMMARY.md:263 +#: src/SUMMARY.md:19 src/SUMMARY.md:79 src/SUMMARY.md:134 src/SUMMARY.md:192 +#: src/SUMMARY.md:218 src/SUMMARY.md:268 msgid "Welcome" msgstr "Velkommen" @@ -120,7 +120,7 @@ msgstr "Funktioner" msgid "Rustdoc" msgstr "" -#: src/SUMMARY.md:36 src/SUMMARY.md:83 src/basic-syntax/methods.md:1 +#: src/SUMMARY.md:36 src/SUMMARY.md:102 src/basic-syntax/methods.md:1 #: src/methods.md:1 msgid "Methods" msgstr "Metoder" @@ -129,9 +129,9 @@ msgstr "Metoder" msgid "Overloading" msgstr "Funktionsoverlæsning" -#: src/SUMMARY.md:38 src/SUMMARY.md:67 src/SUMMARY.md:91 src/SUMMARY.md:121 -#: src/SUMMARY.md:150 src/SUMMARY.md:179 src/SUMMARY.md:206 src/SUMMARY.md:227 -#: src/SUMMARY.md:255 src/SUMMARY.md:277 src/SUMMARY.md:298 +#: src/SUMMARY.md:38 src/SUMMARY.md:71 src/SUMMARY.md:105 src/SUMMARY.md:125 +#: src/SUMMARY.md:154 src/SUMMARY.md:184 src/SUMMARY.md:211 src/SUMMARY.md:232 +#: src/SUMMARY.md:260 src/SUMMARY.md:282 src/SUMMARY.md:303 #: src/exercises/android/morning.md:1 src/exercises/bare-metal/morning.md:1 #: src/exercises/bare-metal/afternoon.md:1 #: src/exercises/concurrency/morning.md:1 @@ -151,876 +151,879 @@ msgstr "Arrays og for-løkker" msgid "Day 1: Afternoon" msgstr "Dag 1: Eftermiddag" -#: src/SUMMARY.md:44 src/basic-syntax/variables.md:1 +#: src/SUMMARY.md:44 src/SUMMARY.md:295 src/control-flow.md:1 +msgid "Control Flow" +msgstr "Forgreninger" + +#: src/SUMMARY.md:45 src/control-flow/blocks.md:1 +msgid "Blocks" +msgstr "Blokke" + +#: src/SUMMARY.md:46 +msgid "if expressions" +msgstr "if udtryk" + +#: src/SUMMARY.md:47 +msgid "for expressions" +msgstr "for udtryk" + +#: src/SUMMARY.md:48 +msgid "while expressions" +msgstr "while udtryk" + +#: src/SUMMARY.md:49 +msgid "break & continue" +msgstr "break og continue" + +#: src/SUMMARY.md:50 +msgid "loop expressions" +msgstr "loop udtryk" + +#: src/SUMMARY.md:52 src/basic-syntax/variables.md:1 msgid "Variables" msgstr "Variabler" -#: src/SUMMARY.md:45 src/basic-syntax/type-inference.md:1 +#: src/SUMMARY.md:53 src/basic-syntax/type-inference.md:1 msgid "Type Inference" msgstr "Typeudledning" -#: src/SUMMARY.md:46 +#: src/SUMMARY.md:54 msgid "static & const" msgstr "static & const" -#: src/SUMMARY.md:47 src/basic-syntax/scopes-shadowing.md:1 +#: src/SUMMARY.md:55 src/basic-syntax/scopes-shadowing.md:1 msgid "Scopes and Shadowing" msgstr "Virkefelt og overskyggede variabler" -#: src/SUMMARY.md:48 src/memory-management.md:1 -msgid "Memory Management" -msgstr "Håndtering af hukommelse" - -#: src/SUMMARY.md:49 -msgid "Stack vs Heap" -msgstr "Stak og heap" - -#: src/SUMMARY.md:50 -msgid "Stack Memory" -msgstr "Stakhukommelse" - -#: src/SUMMARY.md:51 src/memory-management/manual.md:1 -msgid "Manual Memory Management" -msgstr "Manuel hukommelseshåndtering" - -#: src/SUMMARY.md:52 src/memory-management/scope-based.md:1 -msgid "Scope-Based Memory Management" -msgstr "Hukommelseshåndtering baseret på virkefelt" - -#: src/SUMMARY.md:53 -msgid "Garbage Collection" -msgstr "Automatisk hukommelseshåndtering" - -#: src/SUMMARY.md:54 -msgid "Rust Memory Management" -msgstr "Hukommelseshåndtering i Rust" - -#: src/SUMMARY.md:55 src/memory-management/comparison.md:1 -msgid "Comparison" -msgstr "Sammenligning" - -#: src/SUMMARY.md:56 src/ownership.md:1 -msgid "Ownership" -msgstr "Ejerskab" - -#: src/SUMMARY.md:57 src/ownership/move-semantics.md:1 -msgid "Move Semantics" -msgstr "Overførselssemantik" - -#: src/SUMMARY.md:58 src/ownership/moved-strings-rust.md:1 -msgid "Moved Strings in Rust" -msgstr "Overførte strenge i Rust" - -#: src/SUMMARY.md:59 -msgid "Double Frees in Modern C++" -msgstr "Dobbeltfrigivelser i moderne C++" - -#: src/SUMMARY.md:60 src/ownership/moves-function-calls.md:1 -msgid "Moves in Function Calls" -msgstr "Overførsel af ejerskab i funktionskald" - -#: src/SUMMARY.md:61 src/ownership/copy-clone.md:1 -msgid "Copying and Cloning" -msgstr "Kopiering og kloning" - -#: src/SUMMARY.md:62 src/ownership/borrowing.md:1 -msgid "Borrowing" -msgstr "Lån af variabler" - -#: src/SUMMARY.md:63 src/ownership/shared-unique-borrows.md:1 -msgid "Shared and Unique Borrows" -msgstr "Delte og unikke lån" - -#: src/SUMMARY.md:64 src/ownership/lifetimes.md:1 -msgid "Lifetimes" -msgstr "Livstider" - -#: src/SUMMARY.md:65 src/ownership/lifetimes-function-calls.md:1 -msgid "Lifetimes in Function Calls" -msgstr "Livstider i funktionskald" - -#: src/SUMMARY.md:66 src/ownership/lifetimes-data-structures.md:1 -msgid "Lifetimes in Data Structures" -msgstr "Livstider i datastrukturer" - -#: src/SUMMARY.md:68 src/exercises/day-1/book-library.md:1 -msgid "Storing Books" -msgstr "Lagring af bøger" - -#: src/SUMMARY.md:69 src/exercises/day-1/iterators-and-ownership.md:1 -msgid "Iterators and Ownership" -msgstr "Iteratorer og ejerskab" - -#: src/SUMMARY.md:72 -msgid "Day 2: Morning" -msgstr "Dag 2: Formiddag" - -#: src/SUMMARY.md:77 src/structs.md:1 -msgid "Structs" -msgstr "Strukturer" - -#: src/SUMMARY.md:78 src/structs/tuple-structs.md:1 -msgid "Tuple Structs" -msgstr "Tuple-strukturer" - -#: src/SUMMARY.md:79 src/structs/field-shorthand.md:1 -msgid "Field Shorthand Syntax" -msgstr "Forenklet strukturinitialisering" - -#: src/SUMMARY.md:80 src/enums.md:1 +#: src/SUMMARY.md:56 src/enums.md:1 msgid "Enums" msgstr "Enumerationer" -#: src/SUMMARY.md:81 src/enums/variant-payloads.md:1 +#: src/SUMMARY.md:57 src/enums/variant-payloads.md:1 msgid "Variant Payloads" msgstr "Nyttelast i varianter" -#: src/SUMMARY.md:82 src/enums/sizes.md:1 +#: src/SUMMARY.md:58 src/enums/sizes.md:1 msgid "Enum Sizes" msgstr "Størrelse af enumerationer" -#: src/SUMMARY.md:84 src/methods/receiver.md:1 +#: src/SUMMARY.md:60 src/control-flow/novel.md:1 +msgid "Novel Control Flow" +msgstr "Usædvanlige forgreninger" + +#: src/SUMMARY.md:61 +msgid "if let expressions" +msgstr "if let udtryk" + +#: src/SUMMARY.md:62 +msgid "while let expressions" +msgstr "while let udtryk" + +#: src/SUMMARY.md:63 +msgid "match expressions" +msgstr "match udtryk" + +#: src/SUMMARY.md:65 src/pattern-matching.md:1 +msgid "Pattern Matching" +msgstr "Mønstergenkendelse" + +#: src/SUMMARY.md:66 src/pattern-matching/destructuring-enums.md:1 +msgid "Destructuring Enums" +msgstr "Dekonstruktion af enumerationer" + +#: src/SUMMARY.md:67 src/pattern-matching/destructuring-structs.md:1 +msgid "Destructuring Structs" +msgstr "Dekonstruktion af strukturer" + +#: src/SUMMARY.md:68 src/pattern-matching/destructuring-arrays.md:1 +msgid "Destructuring Arrays" +msgstr "Dekonstruktion af arrays" + +#: src/SUMMARY.md:69 src/pattern-matching/match-guards.md:1 +msgid "Match Guards" +msgstr "" + +#: src/SUMMARY.md:72 src/exercises/day-1/luhn.md:1 +#: src/exercises/day-1/solutions-afternoon.md:3 +msgid "Luhn Algorithm" +msgstr "Luhn-algorithmen" + +#: src/SUMMARY.md:73 +msgid "Pattern Matching (TBD)" +msgstr "Mønstergenkendelse (mangler)" + +#: src/SUMMARY.md:75 +msgid "Day 2: Morning" +msgstr "Dag 2: Formiddag" + +#: src/SUMMARY.md:81 src/memory-management.md:1 +msgid "Memory Management" +msgstr "Håndtering af hukommelse" + +#: src/SUMMARY.md:82 +msgid "Stack vs Heap" +msgstr "Stak og heap" + +#: src/SUMMARY.md:83 +msgid "Stack Memory" +msgstr "Stakhukommelse" + +#: src/SUMMARY.md:84 src/memory-management/manual.md:1 +msgid "Manual Memory Management" +msgstr "Manuel hukommelseshåndtering" + +#: src/SUMMARY.md:85 src/memory-management/scope-based.md:1 +msgid "Scope-Based Memory Management" +msgstr "Hukommelseshåndtering baseret på virkefelt" + +#: src/SUMMARY.md:86 +msgid "Garbage Collection" +msgstr "Automatisk hukommelseshåndtering" + +#: src/SUMMARY.md:87 +msgid "Rust Memory Management" +msgstr "Hukommelseshåndtering i Rust" + +#: src/SUMMARY.md:88 src/ownership.md:1 +msgid "Ownership" +msgstr "Ejerskab" + +#: src/SUMMARY.md:89 src/ownership/move-semantics.md:1 +msgid "Move Semantics" +msgstr "Overførselssemantik" + +#: src/SUMMARY.md:90 src/ownership/moved-strings-rust.md:1 +msgid "Moved Strings in Rust" +msgstr "Overførte strenge i Rust" + +#: src/SUMMARY.md:91 +msgid "Double Frees in Modern C++" +msgstr "Dobbeltfrigivelser i moderne C++" + +#: src/SUMMARY.md:92 src/ownership/moves-function-calls.md:1 +msgid "Moves in Function Calls" +msgstr "Overførsel af ejerskab i funktionskald" + +#: src/SUMMARY.md:93 src/ownership/copy-clone.md:1 +msgid "Copying and Cloning" +msgstr "Kopiering og kloning" + +#: src/SUMMARY.md:94 src/ownership/borrowing.md:1 +msgid "Borrowing" +msgstr "Lån af variabler" + +#: src/SUMMARY.md:95 src/ownership/shared-unique-borrows.md:1 +msgid "Shared and Unique Borrows" +msgstr "Delte og unikke lån" + +#: src/SUMMARY.md:96 src/ownership/lifetimes.md:1 +msgid "Lifetimes" +msgstr "Livstider" + +#: src/SUMMARY.md:97 src/ownership/lifetimes-function-calls.md:1 +msgid "Lifetimes in Function Calls" +msgstr "Livstider i funktionskald" + +#: src/SUMMARY.md:98 src/ownership/lifetimes-data-structures.md:1 +msgid "Lifetimes in Data Structures" +msgstr "Livstider i datastrukturer" + +#: src/SUMMARY.md:99 src/structs.md:1 +msgid "Structs" +msgstr "Strukturer" + +#: src/SUMMARY.md:100 src/structs/tuple-structs.md:1 +msgid "Tuple Structs" +msgstr "Tuple-strukturer" + +#: src/SUMMARY.md:101 src/structs/field-shorthand.md:1 +msgid "Field Shorthand Syntax" +msgstr "Forenklet strukturinitialisering" + +#: src/SUMMARY.md:103 src/methods/receiver.md:1 msgid "Method Receiver" msgstr "Modtager af funktionskald" -#: src/SUMMARY.md:85 src/SUMMARY.md:161 src/SUMMARY.md:276 +#: src/SUMMARY.md:104 src/SUMMARY.md:166 src/SUMMARY.md:281 #: src/methods/example.md:1 src/concurrency/shared_state/example.md:1 msgid "Example" msgstr "Eksempel" -#: src/SUMMARY.md:86 src/pattern-matching.md:1 -msgid "Pattern Matching" -msgstr "Mønstergenkendelse" +#: src/SUMMARY.md:106 src/exercises/day-2/book-library.md:1 +msgid "Storing Books" +msgstr "Lagring af bøger" -#: src/SUMMARY.md:87 src/pattern-matching/destructuring-enums.md:1 -msgid "Destructuring Enums" -msgstr "Dekonstruktion af enumerationer" - -#: src/SUMMARY.md:88 src/pattern-matching/destructuring-structs.md:1 -msgid "Destructuring Structs" -msgstr "Dekonstruktion af strukturer" - -#: src/SUMMARY.md:89 src/pattern-matching/destructuring-arrays.md:1 -msgid "Destructuring Arrays" -msgstr "Dekonstruktion af arrays" - -#: src/SUMMARY.md:90 src/pattern-matching/match-guards.md:1 -msgid "Match Guards" -msgstr "" - -#: src/SUMMARY.md:92 src/exercises/day-2/health-statistics.md:1 +#: src/SUMMARY.md:107 src/exercises/day-2/health-statistics.md:1 msgid "Health Statistics" msgstr "" -#: src/SUMMARY.md:93 src/exercises/day-2/solutions-morning.md:3 -msgid "Points and Polygons" -msgstr "Punkter og polygoner" - -#: src/SUMMARY.md:95 +#: src/SUMMARY.md:109 msgid "Day 2: Afternoon" msgstr "Dag 2: Eftermiddag" -#: src/SUMMARY.md:97 src/SUMMARY.md:290 src/control-flow.md:1 -msgid "Control Flow" -msgstr "Forgreninger" - -#: src/SUMMARY.md:98 src/control-flow/blocks.md:1 -msgid "Blocks" -msgstr "Blokke" - -#: src/SUMMARY.md:99 -msgid "if expressions" -msgstr "if udtryk" - -#: src/SUMMARY.md:100 -msgid "if let expressions" -msgstr "if let udtryk" - -#: src/SUMMARY.md:101 -msgid "while expressions" -msgstr "while udtryk" - -#: src/SUMMARY.md:102 -msgid "while let expressions" -msgstr "while let udtryk" - -#: src/SUMMARY.md:103 -msgid "for expressions" -msgstr "for udtryk" - -#: src/SUMMARY.md:104 -msgid "loop expressions" -msgstr "loop udtryk" - -#: src/SUMMARY.md:105 -msgid "match expressions" -msgstr "match udtryk" - -#: src/SUMMARY.md:106 -msgid "break & continue" -msgstr "break og continue" - -#: src/SUMMARY.md:107 src/std.md:1 +#: src/SUMMARY.md:111 src/std.md:1 msgid "Standard Library" msgstr "" -#: src/SUMMARY.md:108 +#: src/SUMMARY.md:112 msgid "Option and Result" msgstr "" -#: src/SUMMARY.md:109 src/std/string.md:1 +#: src/SUMMARY.md:113 src/std/string.md:1 msgid "String" msgstr "" -#: src/SUMMARY.md:110 +#: src/SUMMARY.md:114 msgid "Vec" msgstr "" -#: src/SUMMARY.md:111 +#: src/SUMMARY.md:115 msgid "HashMap" msgstr "" -#: src/SUMMARY.md:112 +#: src/SUMMARY.md:116 msgid "Box" msgstr "" -#: src/SUMMARY.md:113 +#: src/SUMMARY.md:117 msgid "Recursive Data Types" msgstr "" -#: src/SUMMARY.md:114 src/std/box-niche.md:1 +#: src/SUMMARY.md:118 src/std/box-niche.md:1 msgid "Niche Optimization" msgstr "" -#: src/SUMMARY.md:115 +#: src/SUMMARY.md:119 msgid "Rc" msgstr "" -#: src/SUMMARY.md:116 +#: src/SUMMARY.md:120 msgid "Cell/RefCell" msgstr "" -#: src/SUMMARY.md:117 src/modules.md:1 +#: src/SUMMARY.md:121 src/modules.md:1 msgid "Modules" msgstr "" -#: src/SUMMARY.md:118 src/modules/visibility.md:1 +#: src/SUMMARY.md:122 src/modules/visibility.md:1 msgid "Visibility" msgstr "" -#: src/SUMMARY.md:119 src/modules/paths.md:1 +#: src/SUMMARY.md:123 src/modules/paths.md:1 msgid "Paths" msgstr "" -#: src/SUMMARY.md:120 src/modules/filesystem.md:1 +#: src/SUMMARY.md:124 src/modules/filesystem.md:1 msgid "Filesystem Hierarchy" msgstr "" -#: src/SUMMARY.md:122 src/exercises/day-2/luhn.md:1 -#: src/exercises/day-2/solutions-afternoon.md:3 -msgid "Luhn Algorithm" -msgstr "Luhn-algorithmen" +#: src/SUMMARY.md:126 src/exercises/day-2/iterators-and-ownership.md:1 +msgid "Iterators and Ownership" +msgstr "Iteratorer og ejerskab" -#: src/SUMMARY.md:123 src/exercises/day-2/strings-iterators.md:1 -#: src/exercises/day-2/solutions-afternoon.md:97 +#: src/SUMMARY.md:127 src/exercises/day-2/strings-iterators.md:1 +#: src/exercises/day-2/solutions-afternoon.md:3 msgid "Strings and Iterators" msgstr "Strenge og iteratorer" -#: src/SUMMARY.md:126 +#: src/SUMMARY.md:130 msgid "Day 3: Morning" msgstr "" -#: src/SUMMARY.md:131 src/generics.md:1 +#: src/SUMMARY.md:135 src/generics.md:1 msgid "Generics" msgstr "" -#: src/SUMMARY.md:132 src/generics/data-types.md:1 +#: src/SUMMARY.md:136 src/generics/data-types.md:1 msgid "Generic Data Types" msgstr "" -#: src/SUMMARY.md:133 src/generics/methods.md:1 +#: src/SUMMARY.md:137 src/generics/methods.md:1 msgid "Generic Methods" msgstr "" -#: src/SUMMARY.md:134 src/generics/monomorphization.md:1 +#: src/SUMMARY.md:138 src/generics/monomorphization.md:1 msgid "Monomorphization" msgstr "" -#: src/SUMMARY.md:135 src/traits.md:1 +#: src/SUMMARY.md:139 src/traits.md:1 msgid "Traits" msgstr "" -#: src/SUMMARY.md:136 src/traits/trait-objects.md:1 +#: src/SUMMARY.md:140 src/traits/trait-objects.md:1 msgid "Trait Objects" msgstr "" -#: src/SUMMARY.md:137 src/traits/deriving-traits.md:1 +#: src/SUMMARY.md:141 src/traits/deriving-traits.md:1 msgid "Deriving Traits" msgstr "" -#: src/SUMMARY.md:138 src/traits/default-methods.md:1 +#: src/SUMMARY.md:142 src/traits/default-methods.md:1 msgid "Default Methods" msgstr "" -#: src/SUMMARY.md:139 src/traits/trait-bounds.md:1 +#: src/SUMMARY.md:143 src/traits/trait-bounds.md:1 msgid "Trait Bounds" msgstr "" -#: src/SUMMARY.md:140 +#: src/SUMMARY.md:144 msgid "impl Trait" msgstr "" -#: src/SUMMARY.md:141 src/traits/important-traits.md:1 +#: src/SUMMARY.md:145 src/traits/important-traits.md:1 msgid "Important Traits" msgstr "" -#: src/SUMMARY.md:142 +#: src/SUMMARY.md:146 msgid "Iterator" msgstr "" -#: src/SUMMARY.md:143 src/traits/from-iterator.md:1 +#: src/SUMMARY.md:147 src/traits/from-iterator.md:1 msgid "FromIterator" msgstr "" -#: src/SUMMARY.md:144 +#: src/SUMMARY.md:148 msgid "From and Into" msgstr "" -#: src/SUMMARY.md:145 +#: src/SUMMARY.md:149 msgid "Read and Write" msgstr "" -#: src/SUMMARY.md:146 +#: src/SUMMARY.md:150 msgid "Drop" msgstr "" -#: src/SUMMARY.md:147 +#: src/SUMMARY.md:151 msgid "Default" msgstr "" -#: src/SUMMARY.md:148 +#: src/SUMMARY.md:152 msgid "Operators: Add, Mul, ..." msgstr "" -#: src/SUMMARY.md:149 +#: src/SUMMARY.md:153 msgid "Closures: Fn, FnMut, FnOnce" msgstr "" -#: src/SUMMARY.md:151 src/exercises/day-3/simple-gui.md:1 +#: src/SUMMARY.md:155 src/exercises/day-3/simple-gui.md:1 #: src/exercises/day-3/solutions-morning.md:3 msgid "A Simple GUI Library" msgstr "" -#: src/SUMMARY.md:153 +#: src/SUMMARY.md:156 src/exercises/day-3/solutions-morning.md:175 +msgid "Points and Polygons" +msgstr "Punkter og polygoner" + +#: src/SUMMARY.md:158 msgid "Day 3: Afternoon" msgstr "" -#: src/SUMMARY.md:155 src/error-handling.md:1 +#: src/SUMMARY.md:160 src/error-handling.md:1 msgid "Error Handling" msgstr "" -#: src/SUMMARY.md:156 src/error-handling/panics.md:1 +#: src/SUMMARY.md:161 src/error-handling/panics.md:1 msgid "Panics" msgstr "" -#: src/SUMMARY.md:157 +#: src/SUMMARY.md:162 msgid "Catching Stack Unwinding" msgstr "" -#: src/SUMMARY.md:158 +#: src/SUMMARY.md:163 msgid "Structured Error Handling" msgstr "" -#: src/SUMMARY.md:159 +#: src/SUMMARY.md:164 msgid "Propagating Errors with ?" msgstr "" -#: src/SUMMARY.md:160 src/error-handling/converting-error-types.md:1 +#: src/SUMMARY.md:165 src/error-handling/converting-error-types.md:1 #: src/error-handling/converting-error-types-example.md:1 msgid "Converting Error Types" msgstr "" -#: src/SUMMARY.md:162 src/error-handling/deriving-error-enums.md:1 +#: src/SUMMARY.md:167 src/error-handling/deriving-error-enums.md:1 msgid "Deriving Error Enums" msgstr "" -#: src/SUMMARY.md:163 src/error-handling/dynamic-errors.md:1 +#: src/SUMMARY.md:168 src/error-handling/dynamic-errors.md:1 msgid "Dynamic Error Types" msgstr "" -#: src/SUMMARY.md:164 src/error-handling/error-contexts.md:1 +#: src/SUMMARY.md:169 src/error-handling/error-contexts.md:1 msgid "Adding Context to Errors" msgstr "" -#: src/SUMMARY.md:165 src/testing.md:1 +#: src/SUMMARY.md:170 src/testing.md:1 msgid "Testing" msgstr "" -#: src/SUMMARY.md:166 src/testing/unit-tests.md:1 +#: src/SUMMARY.md:171 src/testing/unit-tests.md:1 msgid "Unit Tests" msgstr "" -#: src/SUMMARY.md:167 src/testing/test-modules.md:1 +#: src/SUMMARY.md:172 src/testing/test-modules.md:1 msgid "Test Modules" msgstr "" -#: src/SUMMARY.md:168 src/testing/doc-tests.md:1 +#: src/SUMMARY.md:173 src/testing/doc-tests.md:1 msgid "Documentation Tests" msgstr "" -#: src/SUMMARY.md:169 src/testing/integration-tests.md:1 +#: src/SUMMARY.md:174 src/testing/integration-tests.md:1 msgid "Integration Tests" msgstr "" -#: src/SUMMARY.md:170 src/bare-metal/useful-crates.md:1 +#: src/SUMMARY.md:175 src/bare-metal/useful-crates.md:1 msgid "Useful crates" msgstr "" -#: src/SUMMARY.md:171 src/unsafe.md:1 +#: src/SUMMARY.md:176 src/unsafe.md:1 msgid "Unsafe Rust" msgstr "" -#: src/SUMMARY.md:172 src/unsafe/raw-pointers.md:1 +#: src/SUMMARY.md:177 src/unsafe/raw-pointers.md:1 msgid "Dereferencing Raw Pointers" msgstr "" -#: src/SUMMARY.md:173 src/unsafe/mutable-static-variables.md:1 +#: src/SUMMARY.md:178 src/unsafe/mutable-static-variables.md:1 msgid "Mutable Static Variables" msgstr "" -#: src/SUMMARY.md:174 src/unsafe/unions.md:1 +#: src/SUMMARY.md:179 src/unsafe/unions.md:1 msgid "Unions" msgstr "" -#: src/SUMMARY.md:175 src/unsafe/calling-unsafe-functions.md:1 +#: src/SUMMARY.md:180 src/unsafe/calling-unsafe-functions.md:1 msgid "Calling Unsafe Functions" msgstr "" -#: src/SUMMARY.md:176 src/unsafe/writing-unsafe-functions.md:1 +#: src/SUMMARY.md:181 src/unsafe/writing-unsafe-functions.md:1 msgid "Writing Unsafe Functions" msgstr "" -#: src/SUMMARY.md:177 +#: src/SUMMARY.md:182 msgid "Extern Functions" msgstr "" -#: src/SUMMARY.md:178 src/unsafe/unsafe-traits.md:1 +#: src/SUMMARY.md:183 src/unsafe/unsafe-traits.md:1 msgid "Implementing Unsafe Traits" msgstr "" -#: src/SUMMARY.md:180 src/exercises/day-3/safe-ffi-wrapper.md:1 +#: src/SUMMARY.md:185 src/exercises/day-3/safe-ffi-wrapper.md:1 #: src/exercises/day-3/solutions-afternoon.md:3 msgid "Safe FFI Wrapper" msgstr "" -#: src/SUMMARY.md:183 src/SUMMARY.md:253 -#: src/running-the-course/course-structure.md:16 src/bare-metal/android.md:1 +#: src/SUMMARY.md:188 src/SUMMARY.md:258 src/bare-metal/android.md:1 msgid "Android" msgstr "Android" -#: src/SUMMARY.md:188 src/android/setup.md:1 +#: src/SUMMARY.md:193 src/android/setup.md:1 msgid "Setup" msgstr "" -#: src/SUMMARY.md:189 src/android/build-rules.md:1 +#: src/SUMMARY.md:194 src/android/build-rules.md:1 msgid "Build Rules" msgstr "" -#: src/SUMMARY.md:190 +#: src/SUMMARY.md:195 msgid "Binary" msgstr "" -#: src/SUMMARY.md:191 +#: src/SUMMARY.md:196 msgid "Library" msgstr "" -#: src/SUMMARY.md:192 src/android/aidl.md:1 +#: src/SUMMARY.md:197 src/android/aidl.md:1 msgid "AIDL" msgstr "" -#: src/SUMMARY.md:193 +#: src/SUMMARY.md:198 msgid "Interface" msgstr "" -#: src/SUMMARY.md:194 +#: src/SUMMARY.md:199 msgid "Implementation" msgstr "" -#: src/SUMMARY.md:195 +#: src/SUMMARY.md:200 msgid "Server" msgstr "" -#: src/SUMMARY.md:196 src/android/aidl/deploy.md:1 +#: src/SUMMARY.md:201 src/android/aidl/deploy.md:1 msgid "Deploy" msgstr "" -#: src/SUMMARY.md:197 +#: src/SUMMARY.md:202 msgid "Client" msgstr "" -#: src/SUMMARY.md:198 src/android/aidl/changing.md:1 +#: src/SUMMARY.md:203 src/android/aidl/changing.md:1 msgid "Changing API" msgstr "" -#: src/SUMMARY.md:199 src/SUMMARY.md:243 src/android/logging.md:1 +#: src/SUMMARY.md:204 src/SUMMARY.md:248 src/android/logging.md:1 #: src/bare-metal/aps/logging.md:1 msgid "Logging" msgstr "" -#: src/SUMMARY.md:200 src/android/interoperability.md:1 +#: src/SUMMARY.md:205 src/android/interoperability.md:1 msgid "Interoperability" msgstr "" -#: src/SUMMARY.md:201 +#: src/SUMMARY.md:206 msgid "With C" msgstr "" -#: src/SUMMARY.md:202 +#: src/SUMMARY.md:207 msgid "Calling C with Bindgen" msgstr "" -#: src/SUMMARY.md:203 +#: src/SUMMARY.md:208 msgid "Calling Rust from C" msgstr "" -#: src/SUMMARY.md:204 src/android/interoperability/cpp.md:1 +#: src/SUMMARY.md:209 src/android/interoperability/cpp.md:1 msgid "With C++" msgstr "" -#: src/SUMMARY.md:205 +#: src/SUMMARY.md:210 msgid "With Java" msgstr "" -#: src/SUMMARY.md:209 +#: src/SUMMARY.md:214 msgid "Bare Metal: Morning" msgstr "Rå jern: Formiddag" -#: src/SUMMARY.md:214 +#: src/SUMMARY.md:219 msgid "no_std" msgstr "no_std" -#: src/SUMMARY.md:215 +#: src/SUMMARY.md:220 msgid "A Minimal Example" msgstr "Et minimalt eksempel" -#: src/SUMMARY.md:216 +#: src/SUMMARY.md:221 msgid "alloc" msgstr "alloc" -#: src/SUMMARY.md:217 src/bare-metal/microcontrollers.md:1 +#: src/SUMMARY.md:222 src/bare-metal/microcontrollers.md:1 msgid "Microcontrollers" msgstr "" -#: src/SUMMARY.md:218 src/bare-metal/microcontrollers/mmio.md:1 +#: src/SUMMARY.md:223 src/bare-metal/microcontrollers/mmio.md:1 msgid "Raw MMIO" msgstr "Rå MMIO" -#: src/SUMMARY.md:219 +#: src/SUMMARY.md:224 msgid "PACs" msgstr "PAC'er" -#: src/SUMMARY.md:220 +#: src/SUMMARY.md:225 msgid "HAL Crates" msgstr "" -#: src/SUMMARY.md:221 +#: src/SUMMARY.md:226 msgid "Board Support Crates" msgstr "" -#: src/SUMMARY.md:222 +#: src/SUMMARY.md:227 msgid "The Type State Pattern" msgstr "" -#: src/SUMMARY.md:223 +#: src/SUMMARY.md:228 msgid "embedded-hal" msgstr "embedded-hal" -#: src/SUMMARY.md:224 +#: src/SUMMARY.md:229 msgid "probe-rs, cargo-embed" msgstr "probe-rs, cargo-embed" -#: src/SUMMARY.md:225 src/bare-metal/microcontrollers/debugging.md:1 +#: src/SUMMARY.md:230 src/bare-metal/microcontrollers/debugging.md:1 msgid "Debugging" msgstr "Fejlfinding" -#: src/SUMMARY.md:226 src/SUMMARY.md:246 +#: src/SUMMARY.md:231 src/SUMMARY.md:251 msgid "Other Projects" msgstr "Andre projekter" -#: src/SUMMARY.md:228 src/exercises/bare-metal/compass.md:1 +#: src/SUMMARY.md:233 src/exercises/bare-metal/compass.md:1 #: src/exercises/bare-metal/solutions-morning.md:3 msgid "Compass" msgstr "Kompas" -#: src/SUMMARY.md:230 +#: src/SUMMARY.md:235 msgid "Bare Metal: Afternoon" msgstr "Rå jern: Eftermiddag" -#: src/SUMMARY.md:232 +#: src/SUMMARY.md:237 msgid "Application Processors" msgstr "" -#: src/SUMMARY.md:233 src/bare-metal/aps/entry-point.md:1 +#: src/SUMMARY.md:238 src/bare-metal/aps/entry-point.md:1 msgid "Getting Ready to Rust" msgstr "" -#: src/SUMMARY.md:234 +#: src/SUMMARY.md:239 msgid "Inline Assembly" msgstr "" -#: src/SUMMARY.md:235 +#: src/SUMMARY.md:240 msgid "MMIO" msgstr "MMIO" -#: src/SUMMARY.md:236 +#: src/SUMMARY.md:241 msgid "Let's Write a UART Driver" msgstr "" -#: src/SUMMARY.md:237 +#: src/SUMMARY.md:242 msgid "More Traits" msgstr "" -#: src/SUMMARY.md:238 +#: src/SUMMARY.md:243 msgid "A Better UART Driver" msgstr "" -#: src/SUMMARY.md:239 src/bare-metal/aps/better-uart/bitflags.md:1 +#: src/SUMMARY.md:244 src/bare-metal/aps/better-uart/bitflags.md:1 msgid "Bitflags" msgstr "Bitflag" -#: src/SUMMARY.md:240 +#: src/SUMMARY.md:245 msgid "Multiple Registers" msgstr "" -#: src/SUMMARY.md:241 src/bare-metal/aps/better-uart/driver.md:1 +#: src/SUMMARY.md:246 src/bare-metal/aps/better-uart/driver.md:1 msgid "Driver" msgstr "Driver" -#: src/SUMMARY.md:242 src/SUMMARY.md:244 +#: src/SUMMARY.md:247 src/SUMMARY.md:249 msgid "Using It" msgstr "Anvendelse" -#: src/SUMMARY.md:245 src/bare-metal/aps/exceptions.md:1 +#: src/SUMMARY.md:250 src/bare-metal/aps/exceptions.md:1 msgid "Exceptions" msgstr "Undtagelser" -#: src/SUMMARY.md:247 +#: src/SUMMARY.md:252 msgid "Useful Crates" msgstr "" -#: src/SUMMARY.md:248 +#: src/SUMMARY.md:253 msgid "zerocopy" msgstr "zerocopy" -#: src/SUMMARY.md:249 +#: src/SUMMARY.md:254 msgid "aarch64-paging" msgstr "aarch64-paging" -#: src/SUMMARY.md:250 +#: src/SUMMARY.md:255 msgid "buddy_system_allocator" msgstr "buddy_system_allocator" -#: src/SUMMARY.md:251 +#: src/SUMMARY.md:256 msgid "tinyvec" msgstr "tinyvec" -#: src/SUMMARY.md:252 +#: src/SUMMARY.md:257 msgid "spin" msgstr "spin" -#: src/SUMMARY.md:254 src/bare-metal/android/vmbase.md:1 +#: src/SUMMARY.md:259 src/bare-metal/android/vmbase.md:1 msgid "vmbase" msgstr "vmbase" -#: src/SUMMARY.md:256 +#: src/SUMMARY.md:261 msgid "RTC Driver" msgstr "" -#: src/SUMMARY.md:259 +#: src/SUMMARY.md:264 msgid "Concurrency: Morning" msgstr "" -#: src/SUMMARY.md:264 src/concurrency/threads.md:1 +#: src/SUMMARY.md:269 src/concurrency/threads.md:1 msgid "Threads" msgstr "Tråde" -#: src/SUMMARY.md:265 src/concurrency/scoped-threads.md:1 +#: src/SUMMARY.md:270 src/concurrency/scoped-threads.md:1 msgid "Scoped Threads" msgstr "Tråde med virkefelt" -#: src/SUMMARY.md:266 src/concurrency/channels.md:1 +#: src/SUMMARY.md:271 src/concurrency/channels.md:1 msgid "Channels" msgstr "Kanaler" -#: src/SUMMARY.md:267 src/concurrency/channels/unbounded.md:1 +#: src/SUMMARY.md:272 src/concurrency/channels/unbounded.md:1 msgid "Unbounded Channels" msgstr "Ubegrænsede kanaler" -#: src/SUMMARY.md:268 src/concurrency/channels/bounded.md:1 +#: src/SUMMARY.md:273 src/concurrency/channels/bounded.md:1 msgid "Bounded Channels" msgstr "Begrænsede kanaler" -#: src/SUMMARY.md:269 +#: src/SUMMARY.md:274 msgid "Send and Sync" msgstr "Send og Sync" -#: src/SUMMARY.md:269 +#: src/SUMMARY.md:274 msgid "Send" msgstr "Send" -#: src/SUMMARY.md:269 +#: src/SUMMARY.md:274 msgid "Sync" msgstr "Sync" -#: src/SUMMARY.md:272 src/concurrency/send-sync/examples.md:1 +#: src/SUMMARY.md:277 src/concurrency/send-sync/examples.md:1 msgid "Examples" msgstr "Eksempler" -#: src/SUMMARY.md:273 src/concurrency/shared_state.md:1 +#: src/SUMMARY.md:278 src/concurrency/shared_state.md:1 msgid "Shared State" msgstr "Delt tilstand" -#: src/SUMMARY.md:274 +#: src/SUMMARY.md:279 msgid "Arc" msgstr "Arc" -#: src/SUMMARY.md:275 +#: src/SUMMARY.md:280 msgid "Mutex" msgstr "Mutex" -#: src/SUMMARY.md:278 src/SUMMARY.md:299 +#: src/SUMMARY.md:283 src/SUMMARY.md:304 #: src/exercises/concurrency/dining-philosophers.md:1 #: src/exercises/concurrency/solutions-morning.md:3 msgid "Dining Philosophers" msgstr "Filosoffer omkring spisebordet" -#: src/SUMMARY.md:279 src/exercises/concurrency/link-checker.md:1 +#: src/SUMMARY.md:284 src/exercises/concurrency/link-checker.md:1 msgid "Multi-threaded Link Checker" msgstr "Flertrådet linktjekker" -#: src/SUMMARY.md:281 +#: src/SUMMARY.md:286 msgid "Concurrency: Afternoon" msgstr "Concurrency: Eftermiddag" -#: src/SUMMARY.md:283 +#: src/SUMMARY.md:288 msgid "Async Basics" msgstr "Grundlæggende Async" -#: src/SUMMARY.md:284 +#: src/SUMMARY.md:289 msgid "async/await" msgstr "async/await" -#: src/SUMMARY.md:285 src/async/futures.md:1 +#: src/SUMMARY.md:290 src/async/futures.md:1 msgid "Futures" msgstr "Fremtidige resultater (eng. Futures)" -#: src/SUMMARY.md:286 src/async/runtimes.md:1 +#: src/SUMMARY.md:291 src/async/runtimes.md:1 msgid "Runtimes" msgstr "" -#: src/SUMMARY.md:287 src/async/runtimes/tokio.md:1 +#: src/SUMMARY.md:292 src/async/runtimes/tokio.md:1 msgid "Tokio" msgstr "Tokio" -#: src/SUMMARY.md:288 src/exercises/concurrency/link-checker.md:126 -#: src/async/tasks.md:1 src/exercises/concurrency/chat-app.md:140 +#: src/SUMMARY.md:293 src/exercises/concurrency/link-checker.md:126 +#: src/async/tasks.md:1 src/exercises/concurrency/chat-app.md:143 msgid "Tasks" msgstr "Opgaver (eng. Tasks)" -#: src/SUMMARY.md:289 src/async/channels.md:1 +#: src/SUMMARY.md:294 src/async/channels.md:1 msgid "Async Channels" msgstr "Asynkrone kanaler" -#: src/SUMMARY.md:291 src/async/control-flow/join.md:1 +#: src/SUMMARY.md:296 src/async/control-flow/join.md:1 msgid "Join" msgstr "Join" -#: src/SUMMARY.md:292 src/async/control-flow/select.md:1 +#: src/SUMMARY.md:297 src/async/control-flow/select.md:1 msgid "Select" msgstr "Select" -#: src/SUMMARY.md:293 +#: src/SUMMARY.md:298 msgid "Pitfalls" msgstr "Faldgruber" -#: src/SUMMARY.md:294 +#: src/SUMMARY.md:299 msgid "Blocking the Executor" msgstr "" -#: src/SUMMARY.md:295 src/async/pitfalls/pin.md:1 +#: src/SUMMARY.md:300 src/async/pitfalls/pin.md:1 msgid "Pin" msgstr "Pin" -#: src/SUMMARY.md:296 src/async/pitfalls/async-traits.md:1 +#: src/SUMMARY.md:301 src/async/pitfalls/async-traits.md:1 msgid "Async Traits" msgstr "Asynkrone egenskaber (eng. Traits)" -#: src/SUMMARY.md:297 src/async/pitfalls/cancellation.md:1 +#: src/SUMMARY.md:302 src/async/pitfalls/cancellation.md:1 msgid "Cancellation" msgstr "Annulering" -#: src/SUMMARY.md:300 src/exercises/concurrency/chat-app.md:1 +#: src/SUMMARY.md:305 src/exercises/concurrency/chat-app.md:1 #: src/exercises/concurrency/solutions-afternoon.md:119 msgid "Broadcast Chat Application" msgstr "Broadcast chat-applikation" -#: src/SUMMARY.md:303 +#: src/SUMMARY.md:308 msgid "Final Words" msgstr "Afsluttende bemærkninger" -#: src/SUMMARY.md:307 src/thanks.md:1 +#: src/SUMMARY.md:312 src/thanks.md:1 msgid "Thanks!" msgstr "Tak!" -#: src/SUMMARY.md:308 +#: src/SUMMARY.md:313 msgid "Other Resources" msgstr "Andre resourcer" -#: src/SUMMARY.md:309 src/credits.md:1 +#: src/SUMMARY.md:314 src/credits.md:1 msgid "Credits" msgstr "Anerkendelser" -#: src/SUMMARY.md:312 src/exercises/solutions.md:1 +#: src/SUMMARY.md:317 src/exercises/solutions.md:1 msgid "Solutions" msgstr "Løsninger" -#: src/SUMMARY.md:317 +#: src/SUMMARY.md:322 msgid "Day 1 Morning" msgstr "Dag 1 Formiddag" -#: src/SUMMARY.md:318 +#: src/SUMMARY.md:323 msgid "Day 1 Afternoon" msgstr "Dag 1 Eftermiddag" -#: src/SUMMARY.md:319 +#: src/SUMMARY.md:324 msgid "Day 2 Morning" msgstr "Dag 2 Formiddag" -#: src/SUMMARY.md:320 +#: src/SUMMARY.md:325 msgid "Day 2 Afternoon" msgstr "Dag 2 Eftermiddag" -#: src/SUMMARY.md:321 +#: src/SUMMARY.md:326 msgid "Day 3 Morning" msgstr "Dag 3 Formiddag" -#: src/SUMMARY.md:322 +#: src/SUMMARY.md:327 msgid "Day 3 Afternoon" msgstr "Dag 3 Eftermiddag" -#: src/SUMMARY.md:323 +#: src/SUMMARY.md:328 msgid "Bare Metal Rust Morning" msgstr "Rå jern Rust formiddag" -#: src/SUMMARY.md:324 src/exercises/bare-metal/solutions-afternoon.md:1 +#: src/SUMMARY.md:329 src/exercises/bare-metal/solutions-afternoon.md:1 msgid "Bare Metal Rust Afternoon" msgstr "Rå jern Rust eftermiddag" -#: src/SUMMARY.md:325 +#: src/SUMMARY.md:330 msgid "Concurrency Morning" msgstr "Parallelprogrammering formiddag" -#: src/SUMMARY.md:326 +#: src/SUMMARY.md:331 msgid "Concurrency Afternoon" msgstr "Parallelprogrammering eftermiddag" @@ -1048,49 +1051,56 @@ msgstr "" #: src/index.md:11 msgid "" +"The latest version of the course can be found at . If you are reading somewhere else, please check there " +"for updates." +msgstr "" + +#: src/index.md:15 +msgid "" "The goal of the course is to teach you Rust. We assume you don't know " "anything about Rust and hope to:" msgstr "" "Målet med kurset er at lære dig Rust. Vi antager, at du ikke ved noget om " "Rust og håber at:" -#: src/index.md:14 +#: src/index.md:18 msgid "Give you a comprehensive understanding of the Rust syntax and language." msgstr "Giver dig en omfattende forståelse af Rust-syntaksen og sproget." -#: src/index.md:15 +#: src/index.md:19 msgid "Enable you to modify existing programs and write new programs in Rust." msgstr "" "Gøre det muligt for dig at ændre eksisterende programmer og skrive nye " "programmer i Rust." -#: src/index.md:16 +#: src/index.md:20 msgid "Show you common Rust idioms." msgstr "Vis dig almindelige Rust idiomer." -#: src/index.md:18 +#: src/index.md:22 msgid "We call the first three course days Rust Fundamentals." msgstr "" -#: src/index.md:20 +#: src/index.md:24 msgid "" "Building on this, you're invited to dive into one or more specialized topics:" msgstr "" -#: src/index.md:22 +#: src/index.md:26 msgid "" "[Android](android.md): a half-day course on using Rust for Android platform " "development (AOSP). This includes interoperability with C, C++, and Java." msgstr "" -#: src/index.md:24 +#: src/index.md:28 msgid "" "[Bare-metal](bare-metal.md): a whole-day class on using Rust for bare-metal " "(embedded) development. Both microcontrollers and application processors are " "covered." msgstr "" -#: src/index.md:27 +#: src/index.md:31 msgid "" "[Concurrency](concurrency.md): a whole-day class on concurrency in Rust. We " "cover both classical concurrency (preemptively scheduling using threads and " @@ -1098,11 +1108,11 @@ msgid "" "futures)." msgstr "" -#: src/index.md:33 +#: src/index.md:37 msgid "Non-Goals" msgstr "Ting som ikke dækkes" -#: src/index.md:35 +#: src/index.md:39 msgid "" "Rust is a large language and we won't be able to cover all of it in a few " "days. Some non-goals of this course are:" @@ -1110,31 +1120,31 @@ msgstr "" "Rust er et stort sprog og vi vil ikke være i stand til at dække det hele på " "et par dage. Nogle af ting som vi ikke dækker er:" -#: src/index.md:38 +#: src/index.md:42 msgid "" "Learning how to develop macros: please see [Chapter 19.5 in the Rust Book]" "(https://doc.rust-lang.org/book/ch19-06-macros.html) and [Rust by Example]" "(https://doc.rust-lang.org/rust-by-example/macros.html) instead." msgstr "" -#: src/index.md:42 +#: src/index.md:46 msgid "Assumptions" msgstr "Antagelser" -#: src/index.md:44 +#: src/index.md:48 msgid "" "The course assumes that you already know how to program. Rust is a " "statically-typed language and we will sometimes make comparisons with C and " "C++ to better explain or contrast the Rust approach." msgstr "" -#: src/index.md:48 +#: src/index.md:52 msgid "" "If you know how to program in a dynamically-typed language such as Python or " "JavaScript, then you will be able to follow along just fine too." msgstr "" -#: src/index.md:53 +#: src/index.md:57 msgid "" "This is an example of a _speaker note_. We will use these to add additional " "information to the slides. This could be key points which the instructor " @@ -1152,10 +1162,20 @@ msgid "" msgstr "" #: src/running-the-course.md:8 +msgid "" +"We typically run classes from 10:00 am to 4:00 pm, with a 1 hour lunch break " +"in the middle. This leaves 2.5 hours for the morning class and 2.5 hours for " +"the afternoon class. Note that this is just a recommendation: you can also " +"spend 3 hour on the morning session to give people more time for exercises. " +"The downside of longer session is that people can become very tired after 6 " +"full hours of class in the afternoon." +msgstr "" + +#: src/running-the-course.md:16 msgid "Before you run the course, you will want to:" msgstr "" -#: src/running-the-course.md:10 +#: src/running-the-course.md:18 msgid "" "Make yourself familiar with the course material. We've included speaker " "notes to help highlight the key points (please help us by contributing more " @@ -1164,7 +1184,7 @@ msgid "" "Notes\"). This way you have a clean screen to present to the class." msgstr "" -#: src/running-the-course.md:16 +#: src/running-the-course.md:24 msgid "" "Decide on the dates. Since the course takes at least three full days, we " "recommend that you schedule the days over two weeks. Course participants " @@ -1172,7 +1192,7 @@ msgid "" "helps them process all the information we give them." msgstr "" -#: src/running-the-course.md:21 +#: src/running-the-course.md:29 msgid "" "Find a room large enough for your in-person participants. We recommend a " "class size of 15-25 people. That's small enough that people are comfortable " @@ -1183,7 +1203,7 @@ msgid "" "instructor, so a lectern won't be very helpful for you." msgstr "" -#: src/running-the-course.md:29 +#: src/running-the-course.md:37 msgid "" "On the day of your course, show up to the room a little early to set things " "up. We recommend presenting directly using `mdbook serve` running on your " @@ -1193,7 +1213,7 @@ msgid "" "you or the course participants spot them." msgstr "" -#: src/running-the-course.md:35 +#: src/running-the-course.md:43 msgid "" "Let people solve the exercises by themselves or in small groups. We " "typically spend 30-45 minutes on exercises in the morning and in the " @@ -1204,13 +1224,13 @@ msgid "" "information in the standard library." msgstr "" -#: src/running-the-course.md:43 +#: src/running-the-course.md:51 msgid "" "That is all, good luck running the course! We hope it will be as much fun " "for you as it has been for us!" msgstr "" -#: src/running-the-course.md:46 +#: src/running-the-course.md:54 msgid "" "Please [provide feedback](https://github.com/google/comprehensive-rust/" "discussions/86) afterwards so that we can keep improving the course. We " @@ -1220,39 +1240,51 @@ msgid "" msgstr "" #: src/running-the-course/course-structure.md:5 -msgid "The course is fast paced and covers a lot of ground:" +msgid "Rust Fundamentals" msgstr "" #: src/running-the-course/course-structure.md:7 -msgid "Day 1: Basic Rust, ownership and the borrow checker." +msgid "" +"The first three days make up [Rust Fundaments](../welcome-day-1.md). The " +"days are fast paced and we cover a lot of ground:" msgstr "" -#: src/running-the-course/course-structure.md:8 -msgid "Day 2: Compound data types, pattern matching, the standard library." -msgstr "" - -#: src/running-the-course/course-structure.md:9 -msgid "Day 3: Traits and generics, error handling, testing, unsafe Rust." +#: src/running-the-course/course-structure.md:10 +msgid "Day 1: Basic Rust, syntax, control flow, creating and consuming values." msgstr "" #: src/running-the-course/course-structure.md:11 +msgid "" +"Day 2: Memory management, ownership, compound data types, and the standard " +"library." +msgstr "" + +#: src/running-the-course/course-structure.md:12 +msgid "Day 3: Generics, traits, error handling, testing, and unsafe Rust." +msgstr "" + +#: src/running-the-course/course-structure.md:14 msgid "Deep Dives" msgstr "" -#: src/running-the-course/course-structure.md:13 +#: src/running-the-course/course-structure.md:16 msgid "" "In addition to the 3-day class on Rust Fundamentals, we cover some more " "specialized topics:" msgstr "" -#: src/running-the-course/course-structure.md:18 +#: src/running-the-course/course-structure.md:19 +msgid "Rust in Android" +msgstr "Rust i Android" + +#: src/running-the-course/course-structure.md:21 msgid "" -"The [Android Deep Dive](../android.md) is a half-day course on using Rust " -"for Android platform development. This includes interoperability with C, C+" -"+, and Java." +"The [Rust in Android](../android.md) deep dive is a half-day course on using " +"Rust for Android platform development. This includes interoperability with " +"C, C++, and Java." msgstr "" -#: src/running-the-course/course-structure.md:22 +#: src/running-the-course/course-structure.md:25 msgid "" "You will need an [AOSP checkout](https://source.android.com/docs/setup/" "download/downloading). Make a checkout of the [course repository](https://" @@ -1261,25 +1293,25 @@ msgid "" "that the Android build system sees the `Android.bp` files in `src/android/`." msgstr "" -#: src/running-the-course/course-structure.md:27 +#: src/running-the-course/course-structure.md:30 msgid "" "Ensure that `adb sync` works with your emulator or real device and pre-build " "all Android examples using `src/android/build_all.sh`. Read the script to " "see the commands it runs and make sure they work when you run them by hand." msgstr "" -#: src/running-the-course/course-structure.md:34 -msgid "Bare-Metal" -msgstr "" +#: src/running-the-course/course-structure.md:37 +msgid "Bare-Metal Rust" +msgstr "Bare-Metal Rust" -#: src/running-the-course/course-structure.md:36 +#: src/running-the-course/course-structure.md:39 msgid "" -"The [Bare-Metal Deep Dive](../bare-metal.md): a full day class on using Rust " -"for bare-metal (embedded) development. Both microcontrollers and application " -"processors are covered." +"The [Bare-Metal Rust](../bare-metal.md) deep dive is a full day class on " +"using Rust for bare-metal (embedded) development. Both microcontrollers and " +"application processors are covered." msgstr "" -#: src/running-the-course/course-structure.md:40 +#: src/running-the-course/course-structure.md:43 msgid "" "For the microcontroller part, you will need to buy the [BBC micro:bit]" "(https://microbit.org/) v2 development board ahead of time. Everybody will " @@ -1287,24 +1319,24 @@ msgid "" "bare-metal.md)." msgstr "" -#: src/running-the-course/course-structure.md:45 -msgid "Concurrency" -msgstr "" - -#: src/running-the-course/course-structure.md:47 -msgid "" -"The [Concurrency Deep Dive](../concurrency.md) is a full day class on " -"classical as well as `async`/`await` concurrency." -msgstr "" +#: src/running-the-course/course-structure.md:48 +msgid "Concurrency in Rust" +msgstr "Samtidighed i Rust" #: src/running-the-course/course-structure.md:50 msgid "" +"The [Concurrency in Rust](../concurrency.md) deep dive is a full day class " +"on classical as well as `async`/`await` concurrency." +msgstr "" + +#: src/running-the-course/course-structure.md:53 +msgid "" "You will need a fresh crate set up and the dependencies downloaded and ready " "to go. You can then copy/paste the examples into `src/main.rs` to experiment " "with them:" msgstr "" -#: src/running-the-course/course-structure.md:54 +#: src/running-the-course/course-structure.md:57 msgid "" "```shell\n" "cargo init concurrency\n" @@ -1320,11 +1352,11 @@ msgstr "" "cargo run\n" "```" -#: src/running-the-course/course-structure.md:61 +#: src/running-the-course/course-structure.md:64 msgid "Format" msgstr "" -#: src/running-the-course/course-structure.md:63 +#: src/running-the-course/course-structure.md:66 msgid "" "The course is meant to be very interactive and we recommend letting the " "questions drive the exploration of Rust!" @@ -1470,11 +1502,11 @@ msgstr "" #: src/cargo.md:18 msgid "" "```shell\n" -" sudo apt install cargo rust-src rustfmt\n" +"sudo apt install cargo rust-src rustfmt\n" "```" msgstr "" "```shell\n" -" sudo apt install cargo rust-src rustfmt\n" +"sudo apt install cargo rust-src rustfmt\n" "```" #: src/cargo.md:22 @@ -1530,6 +1562,7 @@ msgstr "" #: src/why-rust/modern.md:21 src/basic-syntax/compound-types.md:30 #: src/basic-syntax/references.md:23 #: src/pattern-matching/destructuring-enums.md:35 +#: src/ownership/double-free-modern-cpp.md:55 #: src/error-handling/try-operator.md:48 #: src/error-handling/converting-error-types-example.md:50 #: src/concurrency/threads.md:30 src/async/async-await.md:25 @@ -1866,13 +1899,12 @@ msgstr "" #: src/welcome-day-1.md:9 msgid "" -"Memory management: stack vs heap, manual memory management, scope-based " -"memory management, and garbage collection." +"Control flow constructs: `if`, `if let`, `while`, `while let`, `break`, and " +"`continue`." msgstr "" #: src/welcome-day-1.md:12 -msgid "" -"Ownership: move semantics, copying and cloning, borrowing, and lifetimes." +msgid "Pattern matching: destructuring enums, structs, and arrays." msgstr "" #: src/welcome-day-1.md:16 @@ -3345,7 +3377,7 @@ msgid "" msgstr "" #: src/exercises/day-1/morning.md:22 src/exercises/day-2/morning.md:11 -#: src/exercises/day-3/morning.md:7 src/exercises/bare-metal/morning.md:7 +#: src/exercises/day-3/morning.md:9 src/exercises/bare-metal/morning.md:7 #: src/exercises/concurrency/morning.md:12 msgid "" "After looking at the exercises, you can look at the [solutions](solutions-" @@ -3601,8 +3633,310 @@ msgstr "" #: src/exercises/day-1/for-loops.md:102 msgid "" -"An implicit array copy would have occured. Since `i32` is a copy type, then " -"`[i32; 3]` is also a copy type." +"An implicit array copy would have occurred. Since `i32` is a copy type, " +"then `[i32; 3]` is also a copy type." +msgstr "" + +#: src/control-flow.md:3 +msgid "" +"As we have seen, `if` is an expression in Rust. It is used to conditionally " +"evaluate one of two blocks, but the blocks can have a value which then " +"becomes the value of the `if` expression. Other control flow expressions " +"work similarly in Rust." +msgstr "" + +#: src/control-flow/blocks.md:3 +msgid "" +"A block in Rust contains a sequence of expressions. Each block has a value " +"and a type, which are those of the last expression of the block:" +msgstr "" + +#: src/control-flow/blocks.md:7 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let x = {\n" +" let y = 10;\n" +" println!(\"y: {y}\");\n" +" let z = {\n" +" let w = {\n" +" 3 + 4\n" +" };\n" +" println!(\"w: {w}\");\n" +" y * w\n" +" };\n" +" println!(\"z: {z}\");\n" +" z - y\n" +" };\n" +" println!(\"x: {x}\");\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/blocks.md:26 +msgid "" +"If the last expression ends with `;`, then the resulting value and type is " +"`()`." +msgstr "" + +#: src/control-flow/blocks.md:28 +msgid "" +"The same rule is used for functions: the value of the function body is the " +"return value:" +msgstr "" + +#: src/control-flow/blocks.md:31 +msgid "" +"```rust,editable\n" +"fn double(x: i32) -> i32 {\n" +" x + x\n" +"}\n" +"\n" +"fn main() {\n" +" println!(\"doubled: {}\", double(7));\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/blocks.md:43 src/enums.md:34 src/enums/sizes.md:28 +#: src/pattern-matching.md:25 src/pattern-matching/match-guards.md:22 +#: src/structs.md:31 src/methods.md:30 src/methods/example.md:46 +msgid "Key Points:" +msgstr "" + +#: src/control-flow/blocks.md:44 +msgid "" +"The point of this slide is to show that blocks have a type and value in " +"Rust. " +msgstr "" + +#: src/control-flow/blocks.md:45 +msgid "" +"You can show how the value of the block changes by changing the last line in " +"the block. For instance, adding/removing a semicolon or using a `return`." +msgstr "" + +#: src/control-flow/if-expressions.md:1 +msgid "`if` expressions" +msgstr "" + +#: src/control-flow/if-expressions.md:3 +msgid "" +"You use [`if` expressions](https://doc.rust-lang.org/reference/expressions/" +"if-expr.html#if-expressions) exactly like `if` statements in other languages:" +msgstr "" + +#: src/control-flow/if-expressions.md:7 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let mut x = 10;\n" +" if x % 2 == 0 {\n" +" x = x / 2;\n" +" } else {\n" +" x = 3 * x + 1;\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/if-expressions.md:18 +msgid "" +"In addition, you can use `if` as an expression. The last expression of each " +"block becomes the value of the `if` expression:" +msgstr "" + +#: src/control-flow/if-expressions.md:22 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let mut x = 10;\n" +" x = if x % 2 == 0 {\n" +" x / 2\n" +" } else {\n" +" 3 * x + 1\n" +" };\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/if-expressions.md:35 +msgid "" +"Because `if` is an expression and must have a particular type, both of its " +"branch blocks must have the same type. Consider showing what happens if you " +"add `;` after `x / 2` in the second example." +msgstr "" + +#: src/control-flow/for-expressions.md:1 +msgid "`for` loops" +msgstr "" + +#: src/control-flow/for-expressions.md:3 +msgid "" +"The [`for` loop](https://doc.rust-lang.org/std/keyword.for.html) is closely " +"related to the [`while let` loop](while-let-expressions.md). It will " +"automatically call `into_iter()` on the expression and then iterate over it:" +msgstr "" + +#: src/control-flow/for-expressions.md:7 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let v = vec![10, 20, 30];\n" +"\n" +" for x in v {\n" +" println!(\"x: {x}\");\n" +" }\n" +" \n" +" for i in (0..10).step_by(2) {\n" +" println!(\"i: {i}\");\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/for-expressions.md:21 +msgid "You can use `break` and `continue` here as usual." +msgstr "" + +#: src/control-flow/for-expressions.md:25 +msgid "Index iteration is not a special syntax in Rust for just that case." +msgstr "" + +#: src/control-flow/for-expressions.md:26 +msgid "`(0..10)` is a range that implements an `Iterator` trait. " +msgstr "" + +#: src/control-flow/for-expressions.md:27 +msgid "" +"`step_by` is a method that returns another `Iterator` that skips every other " +"element. " +msgstr "" + +#: src/control-flow/for-expressions.md:28 +msgid "" +"Modify the elements in the vector and explain the compiler errors. Change " +"vector `v` to be mutable and the for loop to `for x in v.iter_mut()`." +msgstr "" + +#: src/control-flow/while-expressions.md:1 +msgid "`while` loops" +msgstr "" + +#: src/control-flow/while-expressions.md:3 +msgid "" +"The [`while` keyword](https://doc.rust-lang.org/reference/expressions/loop-" +"expr.html#predicate-loops) works very similar to other languages:" +msgstr "" + +#: src/control-flow/while-expressions.md:6 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let mut x = 10;\n" +" while x != 1 {\n" +" x = if x % 2 == 0 {\n" +" x / 2\n" +" } else {\n" +" 3 * x + 1\n" +" };\n" +" }\n" +" println!(\"Final x: {x}\");\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/break-continue.md:1 +msgid "`break` and `continue`" +msgstr "" + +#: src/control-flow/break-continue.md:3 +msgid "" +"If you want to exit a loop early, use [`break`](https://doc.rust-lang.org/" +"reference/expressions/loop-expr.html#break-expressions)," +msgstr "" + +#: src/control-flow/break-continue.md:4 +msgid "" +"If you want to immediately start the next iteration use [`continue`](https://" +"doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)." +msgstr "" + +#: src/control-flow/break-continue.md:7 +msgid "" +"Both `continue` and `break` can optionally take a label argument which is " +"used to break out of nested loops:" +msgstr "" + +#: src/control-flow/break-continue.md:10 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let v = vec![10, 20, 30];\n" +" let mut iter = v.into_iter();\n" +" 'outer: while let Some(x) = iter.next() {\n" +" println!(\"x: {x}\");\n" +" let mut i = 0;\n" +" while i < x {\n" +" println!(\"x: {x}, i: {i}\");\n" +" i += 1;\n" +" if i == 3 {\n" +" break 'outer;\n" +" }\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/break-continue.md:28 +msgid "" +"In this case we break the outer loop after 3 iterations of the inner loop." +msgstr "" + +#: src/control-flow/loop-expressions.md:1 +msgid "`loop` expressions" +msgstr "" + +#: src/control-flow/loop-expressions.md:3 +msgid "" +"Finally, there is a [`loop` keyword](https://doc.rust-lang.org/reference/" +"expressions/loop-expr.html#infinite-loops) which creates an endless loop." +msgstr "" + +#: src/control-flow/loop-expressions.md:6 +msgid "Here you must either `break` or `return` to stop the loop:" +msgstr "" + +#: src/control-flow/loop-expressions.md:8 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let mut x = 10;\n" +" loop {\n" +" x = if x % 2 == 0 {\n" +" x / 2\n" +" } else {\n" +" 3 * x + 1\n" +" };\n" +" if x == 1 {\n" +" break;\n" +" }\n" +" }\n" +" println!(\"Final x: {x}\");\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/loop-expressions.md:27 +msgid "Break the `loop` with a value (e.g. `break 8`) and print it out." +msgstr "" + +#: src/control-flow/loop-expressions.md:28 +msgid "" +"Note that `loop` is the only looping construct which returns a non-trivial " +"value. This is because it's guaranteed to be entered at least once (unlike " +"`while` and `for` loops)." msgstr "" #: src/basic-syntax/variables.md:3 @@ -3946,6 +4280,988 @@ msgid "" "```" msgstr "" +#: src/enums.md:3 +msgid "" +"The `enum` keyword allows the creation of a type which has a few different " +"variants:" +msgstr "" + +#: src/enums.md:6 +msgid "" +"```rust,editable\n" +"fn generate_random_number() -> i32 {\n" +" // Implementation based on https://xkcd.com/221/\n" +" 4 // Chosen by fair dice roll. Guaranteed to be random.\n" +"}\n" +"\n" +"#[derive(Debug)]\n" +"enum CoinFlip {\n" +" Heads,\n" +" Tails,\n" +"}\n" +"\n" +"fn flip_coin() -> CoinFlip {\n" +" let random_number = generate_random_number();\n" +" if random_number % 2 == 0 {\n" +" return CoinFlip::Heads;\n" +" } else {\n" +" return CoinFlip::Tails;\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" println!(\"You got: {:?}\", flip_coin());\n" +"}\n" +"```" +msgstr "" + +#: src/enums.md:36 +msgid "Enumerations allow you to collect a set of values under one type" +msgstr "" + +#: src/enums.md:37 +msgid "" +"This page offers an enum type `CoinFlip` with two variants `Heads` and " +"`Tails`. You might note the namespace when using variants." +msgstr "" + +#: src/enums.md:38 +msgid "This might be a good time to compare Structs and Enums:" +msgstr "" + +#: src/enums.md:39 +msgid "" +"In both, you can have a simple version without fields (unit struct) or one " +"with different types of fields (variant payloads). " +msgstr "" + +#: src/enums.md:40 +msgid "In both, associated functions are defined within an `impl` block." +msgstr "" + +#: src/enums.md:41 +msgid "" +"You could even implement the different variants of an enum with separate " +"structs but then they wouldn’t be the same type as they would if they were " +"all defined in an enum. " +msgstr "" + +#: src/enums/variant-payloads.md:3 +msgid "" +"You can define richer enums where the variants carry data. You can then use " +"the `match` statement to extract the data from each variant:" +msgstr "" + +#: src/enums/variant-payloads.md:6 +msgid "" +"```rust,editable\n" +"enum WebEvent {\n" +" PageLoad, // Variant without payload\n" +" KeyPress(char), // Tuple struct variant\n" +" Click { x: i64, y: i64 }, // Full struct variant\n" +"}\n" +"\n" +"#[rustfmt::skip]\n" +"fn inspect(event: WebEvent) {\n" +" match event {\n" +" WebEvent::PageLoad => println!(\"page loaded\"),\n" +" WebEvent::KeyPress(c) => println!(\"pressed '{c}'\"),\n" +" WebEvent::Click { x, y } => println!(\"clicked at x={x}, y={y}\"),\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let load = WebEvent::PageLoad;\n" +" let press = WebEvent::KeyPress('x');\n" +" let click = WebEvent::Click { x: 20, y: 80 };\n" +"\n" +" inspect(load);\n" +" inspect(press);\n" +" inspect(click);\n" +"}\n" +"```" +msgstr "" + +#: src/enums/variant-payloads.md:35 +msgid "" +"The values in the enum variants can only be accessed after being pattern " +"matched. The pattern binds references to the fields in the \"match arm\" " +"after the `=>`." +msgstr "" + +#: src/enums/variant-payloads.md:36 +msgid "" +"The expression is matched against the patterns from top to bottom. There is " +"no fall-through like in C or C++." +msgstr "" + +#: src/enums/variant-payloads.md:37 +msgid "" +"The match expression has a value. The value is the last expression in the " +"match arm which was executed." +msgstr "" + +#: src/enums/variant-payloads.md:38 +msgid "" +"Starting from the top we look for what pattern matches the value then run " +"the code following the arrow. Once we find a match, we stop. " +msgstr "" + +#: src/enums/variant-payloads.md:39 +msgid "" +"Demonstrate what happens when the search is inexhaustive. Note the advantage " +"the Rust compiler provides by confirming when all cases are handled. " +msgstr "" + +#: src/enums/variant-payloads.md:40 +msgid "`match` inspects a hidden discriminant field in the `enum`." +msgstr "" + +#: src/enums/variant-payloads.md:41 +msgid "" +"It is possible to retrieve the discriminant by calling `std::mem::" +"discriminant()`" +msgstr "" + +#: src/enums/variant-payloads.md:42 +msgid "" +"This is useful, for example, if implementing `PartialEq` for structs where " +"comparing field values doesn't affect equality." +msgstr "" + +#: src/enums/variant-payloads.md:43 +msgid "" +"`WebEvent::Click { ... }` is not exactly the same as `WebEvent::" +"Click(Click)` with a top level `struct Click { ... }`. The inlined version " +"cannot implement traits, for example." +msgstr "" + +#: src/enums/sizes.md:3 +msgid "" +"Rust enums are packed tightly, taking constraints due to alignment into " +"account:" +msgstr "" + +#: src/enums/sizes.md:5 +msgid "" +"```rust,editable\n" +"use std::any::type_name;\n" +"use std::mem::{align_of, size_of};\n" +"\n" +"fn dbg_size() {\n" +" println!(\"{}: size {} bytes, align: {} bytes\",\n" +" type_name::(), size_of::(), align_of::());\n" +"}\n" +"\n" +"enum Foo {\n" +" A,\n" +" B,\n" +"}\n" +"\n" +"fn main() {\n" +" dbg_size::();\n" +"}\n" +"```" +msgstr "" + +#: src/enums/sizes.md:24 +msgid "" +"See the [Rust Reference](https://doc.rust-lang.org/reference/type-layout." +"html)." +msgstr "" + +#: src/enums/sizes.md:30 +msgid "" +"Internally Rust is using a field (discriminant) to keep track of the enum " +"variant." +msgstr "" + +#: src/enums/sizes.md:32 +msgid "" +"You can control the discriminant if needed (e.g., for compatibility with C):" +msgstr "" + +#: src/enums/sizes.md:34 +msgid "" +"```rust,editable\n" +"#[repr(u32)]\n" +"enum Bar {\n" +" A, // 0\n" +" B = 10000,\n" +" C, // 10001\n" +"}\n" +"\n" +"fn main() {\n" +" println!(\"A: {}\", Bar::A as u32);\n" +" println!(\"B: {}\", Bar::B as u32);\n" +" println!(\"C: {}\", Bar::C as u32);\n" +"}\n" +"```" +msgstr "" + +#: src/enums/sizes.md:49 +msgid "" +"Without `repr`, the discriminant type takes 2 bytes, because 10001 fits 2 " +"bytes." +msgstr "" + +#: src/enums/sizes.md:53 +msgid "Try out other types such as" +msgstr "" + +#: src/enums/sizes.md:55 +msgid "`dbg_size!(bool)`: size 1 bytes, align: 1 bytes," +msgstr "" + +#: src/enums/sizes.md:56 +msgid "" +"`dbg_size!(Option)`: size 1 bytes, align: 1 bytes (niche optimization, " +"see below)," +msgstr "" + +#: src/enums/sizes.md:57 +msgid "`dbg_size!(&i32)`: size 8 bytes, align: 8 bytes (on a 64-bit machine)," +msgstr "" + +#: src/enums/sizes.md:58 +msgid "" +"`dbg_size!(Option<&i32>)`: size 8 bytes, align: 8 bytes (null pointer " +"optimization, see below)." +msgstr "" + +#: src/enums/sizes.md:60 +msgid "" +"Niche optimization: Rust will merge unused bit patterns for the enum " +"discriminant." +msgstr "" + +#: src/enums/sizes.md:63 +msgid "" +"Null pointer optimization: For [some types](https://doc.rust-lang.org/std/" +"option/#representation), Rust guarantees that `size_of::()` equals " +"`size_of::>()`." +msgstr "" + +#: src/enums/sizes.md:67 +msgid "" +"Example code if you want to show how the bitwise representation _may_ look " +"like in practice. It's important to note that the compiler provides no " +"guarantees regarding this representation, therefore this is totally unsafe." +msgstr "" + +#: src/enums/sizes.md:70 +msgid "" +"```rust,editable\n" +"use std::mem::transmute;\n" +"\n" +"macro_rules! dbg_bits {\n" +" ($e:expr, $bit_type:ty) => {\n" +" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, " +"$bit_type>($e));\n" +" };\n" +"}\n" +"\n" +"fn main() {\n" +" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n" +" // representation of types.\n" +" unsafe {\n" +" println!(\"Bitwise representation of bool\");\n" +" dbg_bits!(false, u8);\n" +" dbg_bits!(true, u8);\n" +"\n" +" println!(\"Bitwise representation of Option\");\n" +" dbg_bits!(None::, u8);\n" +" dbg_bits!(Some(false), u8);\n" +" dbg_bits!(Some(true), u8);\n" +"\n" +" println!(\"Bitwise representation of Option>\");\n" +" dbg_bits!(Some(Some(false)), u8);\n" +" dbg_bits!(Some(Some(true)), u8);\n" +" dbg_bits!(Some(None::), u8);\n" +" dbg_bits!(None::>, u8);\n" +"\n" +" println!(\"Bitwise representation of Option<&i32>\");\n" +" dbg_bits!(None::<&i32>, usize);\n" +" dbg_bits!(Some(&0i32), usize);\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/enums/sizes.md:105 +msgid "" +"More complex example if you want to discuss what happens when we chain more " +"than 256 `Option`s together." +msgstr "" + +#: src/enums/sizes.md:107 +msgid "" +"```rust,editable\n" +"#![recursion_limit = \"1000\"]\n" +"\n" +"use std::mem::transmute;\n" +"\n" +"macro_rules! dbg_bits {\n" +" ($e:expr, $bit_type:ty) => {\n" +" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, " +"$bit_type>($e));\n" +" };\n" +"}\n" +"\n" +"// Macro to wrap a value in 2^n Some() where n is the number of \"@\" " +"signs.\n" +"// Increasing the recursion limit is required to evaluate this macro.\n" +"macro_rules! many_options {\n" +" ($value:expr) => { Some($value) };\n" +" ($value:expr, @) => {\n" +" Some(Some($value))\n" +" };\n" +" ($value:expr, @ $($more:tt)+) => {\n" +" many_options!(many_options!($value, $($more)+), $($more)+)\n" +" };\n" +"}\n" +"\n" +"fn main() {\n" +" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n" +" // representation of types.\n" +" unsafe {\n" +" assert_eq!(many_options!(false), Some(false));\n" +" assert_eq!(many_options!(false, @), Some(Some(false)));\n" +" assert_eq!(many_options!(false, @@), " +"Some(Some(Some(Some(false)))));\n" +"\n" +" println!(\"Bitwise representation of a chain of 128 Option's.\");\n" +" dbg_bits!(many_options!(false, @@@@@@@), u8);\n" +" dbg_bits!(many_options!(true, @@@@@@@), u8);\n" +"\n" +" println!(\"Bitwise representation of a chain of 256 Option's.\");\n" +" dbg_bits!(many_options!(false, @@@@@@@@), u16);\n" +" dbg_bits!(many_options!(true, @@@@@@@@), u16);\n" +"\n" +" println!(\"Bitwise representation of a chain of 257 Option's.\");\n" +" dbg_bits!(many_options!(Some(false), @@@@@@@@), u16);\n" +" dbg_bits!(many_options!(Some(true), @@@@@@@@), u16);\n" +" dbg_bits!(many_options!(None::, @@@@@@@@), u16);\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/novel.md:3 +msgid "" +"Rust has a few control flow constructs which differ from other languages. " +"They are used for pattern matching:" +msgstr "" + +#: src/control-flow/novel.md:6 src/control-flow/if-let-expressions.md:1 +msgid "`if let` expressions" +msgstr "" + +#: src/control-flow/novel.md:7 +msgid "`while let` expressions" +msgstr "`while let`-udtryk" + +#: src/control-flow/novel.md:8 src/control-flow/match-expressions.md:1 +msgid "`match` expressions" +msgstr "" + +#: src/control-flow/if-let-expressions.md:3 +msgid "" +"The [`if let` expression](https://doc.rust-lang.org/reference/expressions/if-" +"expr.html#if-let-expressions) lets you execute different code depending on " +"whether a value matches a pattern:" +msgstr "" + +#: src/control-flow/if-let-expressions.md:7 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let arg = std::env::args().next();\n" +" if let Some(value) = arg {\n" +" println!(\"Program name: {value}\");\n" +" } else {\n" +" println!(\"Missing name?\");\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/if-let-expressions.md:18 +#: src/control-flow/while-let-expressions.md:21 +#: src/control-flow/match-expressions.md:23 +msgid "" +"See [pattern matching](../pattern-matching.md) for more details on patterns " +"in Rust." +msgstr "" + +#: src/control-flow/if-let-expressions.md:23 +msgid "" +"Unlike `match`, `if let` does not have to cover all branches. This can make " +"it more concise than `match`." +msgstr "" + +#: src/control-flow/if-let-expressions.md:24 +msgid "A common usage is handling `Some` values when working with `Option`." +msgstr "" + +#: src/control-flow/if-let-expressions.md:25 +msgid "" +"Unlike `match`, `if let` does not support guard clauses for pattern matching." +msgstr "" + +#: src/control-flow/if-let-expressions.md:26 +msgid "" +"Since 1.65, a similar [let-else](https://doc.rust-lang.org/rust-by-example/" +"flow_control/let_else.html) construct allows to do a destructuring " +"assignment, or if it fails, execute a block which is required to abort " +"normal control flow (with `panic`/`return`/`break`/`continue`):" +msgstr "" + +#: src/control-flow/if-let-expressions.md:28 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" println!(\"{:?}\", second_word_to_upper(\"foo bar\"));\n" +"}\n" +" \n" +"fn second_word_to_upper(s: &str) -> Option {\n" +" let mut it = s.split(' ');\n" +" let (Some(_), Some(item)) = (it.next(), it.next()) else {\n" +" return None;\n" +" };\n" +" Some(item.to_uppercase())\n" +"}\n" +"\n" +"```" +msgstr "" + +#: src/control-flow/while-let-expressions.md:1 +msgid "`while let` loops" +msgstr "" + +#: src/control-flow/while-let-expressions.md:3 +msgid "" +"Like with `if let`, there is a [`while let`](https://doc.rust-lang.org/" +"reference/expressions/loop-expr.html#predicate-pattern-loops) variant which " +"repeatedly tests a value against a pattern:" +msgstr "" + +#: src/control-flow/while-let-expressions.md:6 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let v = vec![10, 20, 30];\n" +" let mut iter = v.into_iter();\n" +"\n" +" while let Some(x) = iter.next() {\n" +" println!(\"x: {x}\");\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/while-let-expressions.md:17 +msgid "" +"Here the iterator returned by `v.into_iter()` will return a `Option` on " +"every call to `next()`. It returns `Some(x)` until it is done, after which " +"it will return `None`. The `while let` lets us keep iterating through all " +"items." +msgstr "" + +#: src/control-flow/while-let-expressions.md:26 +msgid "" +"Point out that the `while let` loop will keep going as long as the value " +"matches the pattern." +msgstr "" + +#: src/control-flow/while-let-expressions.md:27 +msgid "" +"You could rewrite the `while let` loop as an infinite loop with an if " +"statement that breaks when there is no value to unwrap for `iter.next()`. " +"The `while let` provides syntactic sugar for the above scenario." +msgstr "" + +#: src/control-flow/match-expressions.md:3 +msgid "" +"The [`match` keyword](https://doc.rust-lang.org/reference/expressions/match-" +"expr.html) is used to match a value against one or more patterns. In that " +"sense, it works like a series of `if let` expressions:" +msgstr "" + +#: src/control-flow/match-expressions.md:7 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" match std::env::args().next().as_deref() {\n" +" Some(\"cat\") => println!(\"Will do cat things\"),\n" +" Some(\"ls\") => println!(\"Will ls some files\"),\n" +" Some(\"mv\") => println!(\"Let's move some files\"),\n" +" Some(\"rm\") => println!(\"Uh, dangerous!\"),\n" +" None => println!(\"Hmm, no program name?\"),\n" +" _ => println!(\"Unknown program name!\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/control-flow/match-expressions.md:20 +msgid "" +"Like `if let`, each match arm must have the same type. The type is the last " +"expression of the block, if any. In the example above, the type is `()`." +msgstr "" + +#: src/control-flow/match-expressions.md:28 +msgid "Save the match expression to a variable and print it out." +msgstr "" + +#: src/control-flow/match-expressions.md:29 +msgid "Remove `.as_deref()` and explain the error." +msgstr "" + +#: src/control-flow/match-expressions.md:30 +msgid "" +"`std::env::args().next()` returns an `Option`, but we cannot match " +"against `String`." +msgstr "" + +#: src/control-flow/match-expressions.md:31 +msgid "" +"`as_deref()` transforms an `Option` to `Option<&T::Target>`. In our case, " +"this turns `Option` into `Option<&str>`." +msgstr "" + +#: src/control-flow/match-expressions.md:32 +msgid "" +"We can now use pattern matching to match against the `&str` inside `Option`." +msgstr "" + +#: src/pattern-matching.md:3 +msgid "" +"The `match` keyword let you match a value against one or more _patterns_. " +"The comparisons are done from top to bottom and the first match wins." +msgstr "" + +#: src/pattern-matching.md:6 +msgid "The patterns can be simple values, similarly to `switch` in C and C++:" +msgstr "" + +#: src/pattern-matching.md:8 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let input = 'x';\n" +"\n" +" match input {\n" +" 'q' => println!(\"Quitting\"),\n" +" 'a' | 's' | 'w' | 'd' => println!(\"Moving around\"),\n" +" '0'..='9' => println!(\"Number input\"),\n" +" _ => println!(\"Something else\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching.md:21 +msgid "The `_` pattern is a wildcard pattern which matches any value." +msgstr "" + +#: src/pattern-matching.md:26 +msgid "" +"You might point out how some specific characters are being used when in a " +"pattern" +msgstr "" + +#: src/pattern-matching.md:27 +msgid "`|` as an `or`" +msgstr "" + +#: src/pattern-matching.md:28 +msgid "`..` can expand as much as it needs to be" +msgstr "" + +#: src/pattern-matching.md:29 +msgid "`1..=5` represents an inclusive range" +msgstr "" + +#: src/pattern-matching.md:30 +msgid "`_` is a wild card" +msgstr "" + +#: src/pattern-matching.md:31 +msgid "" +"It can be useful to show how binding works, by for instance replacing a " +"wildcard character with a variable, or removing the quotes around `q`." +msgstr "" + +#: src/pattern-matching.md:32 +msgid "You can demonstrate matching on a reference." +msgstr "" + +#: src/pattern-matching.md:33 +msgid "" +"This might be a good time to bring up the concept of irrefutable patterns, " +"as the term can show up in error messages." +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:3 +msgid "" +"Patterns can also be used to bind variables to parts of your values. This is " +"how you inspect the structure of your types. Let us start with a simple " +"`enum` type:" +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:6 +msgid "" +"```rust,editable\n" +"enum Result {\n" +" Ok(i32),\n" +" Err(String),\n" +"}\n" +"\n" +"fn divide_in_two(n: i32) -> Result {\n" +" if n % 2 == 0 {\n" +" Result::Ok(n / 2)\n" +" } else {\n" +" Result::Err(format!(\"cannot divide {n} into two equal parts\"))\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let n = 100;\n" +" match divide_in_two(n) {\n" +" Result::Ok(half) => println!(\"{n} divided in two is {half}\"),\n" +" Result::Err(msg) => println!(\"sorry, an error happened: {msg}\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:29 +msgid "" +"Here we have used the arms to _destructure_ the `Result` value. In the first " +"arm, `half` is bound to the value inside the `Ok` variant. In the second " +"arm, `msg` is bound to the error message." +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:36 +msgid "" +"The `if`/`else` expression is returning an enum that is later unpacked with " +"a `match`." +msgstr "" + +#: src/pattern-matching/destructuring-enums.md:37 +msgid "" +"You can try adding a third variant to the enum definition and displaying the " +"errors when running the code. Point out the places where your code is now " +"inexhaustive and how the compiler tries to give you hints." +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:3 +msgid "You can also destructure `structs`:" +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:5 +msgid "" +"```rust,editable\n" +"struct Foo {\n" +" x: (u32, u32),\n" +" y: u32,\n" +"}\n" +"\n" +"#[rustfmt::skip]\n" +"fn main() {\n" +" let foo = Foo { x: (1, 2), y: 3 };\n" +" match foo {\n" +" Foo { x: (1, b), y } => println!(\"x.0 = 1, b = {b}, y = {y}\"),\n" +" Foo { y: 2, x: i } => println!(\"y = 2, x = {i:?}\"),\n" +" Foo { y, .. } => println!(\"y = {y}, other fields were " +"ignored\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:23 +msgid "Change the literal values in `foo` to match with the other patterns." +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:24 +msgid "Add a new field to `Foo` and make changes to the pattern as needed." +msgstr "" + +#: src/pattern-matching/destructuring-structs.md:25 +msgid "" +"The distinction between a capture and a constant expression can be hard to " +"spot. Try changing the `2` in the second arm to a variable, and see that it " +"subtly doesn't work. Change it to a `const` and see it working again." +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:3 +msgid "" +"You can destructure arrays, tuples, and slices by matching on their elements:" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:5 +msgid "" +"```rust,editable\n" +"#[rustfmt::skip]\n" +"fn main() {\n" +" let triple = [0, -2, 3];\n" +" println!(\"Tell me about {triple:?}\");\n" +" match triple {\n" +" [0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" +" [1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" +" _ => println!(\"All elements were ignored\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:21 +msgid "" +"Destructuring of slices of unknown length also works with patterns of fixed " +"length." +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:24 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" inspect(&[0, -2, 3]);\n" +" inspect(&[0, -2, 3, 4]);\n" +"}\n" +"\n" +"#[rustfmt::skip]\n" +"fn inspect(slice: &[i32]) {\n" +" println!(\"Tell me about {slice:?}\");\n" +" match slice {\n" +" &[0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" +" &[1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" +" _ => println!(\"All elements were ignored\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:41 +msgid "Create a new pattern using `_` to represent an element. " +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:42 +msgid "Add more values to the array." +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:43 +msgid "" +"Point out that how `..` will expand to account for different number of " +"elements." +msgstr "" + +#: src/pattern-matching/destructuring-arrays.md:44 +msgid "Show matching against the tail with patterns `[.., b]` and `[a@..,b]`" +msgstr "" + +#: src/pattern-matching/match-guards.md:3 +msgid "" +"When matching, you can add a _guard_ to a pattern. This is an arbitrary " +"Boolean expression which will be executed if the pattern matches:" +msgstr "" + +#: src/pattern-matching/match-guards.md:6 +msgid "" +"```rust,editable\n" +"#[rustfmt::skip]\n" +"fn main() {\n" +" let pair = (2, -2);\n" +" println!(\"Tell me about {pair:?}\");\n" +" match pair {\n" +" (x, y) if x == y => println!(\"These are twins\"),\n" +" (x, y) if x + y == 0 => println!(\"Antimatter, kaboom!\"),\n" +" (x, _) if x % 2 == 1 => println!(\"The first one is odd\"),\n" +" _ => println!(\"No correlation...\"),\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/pattern-matching/match-guards.md:23 +msgid "" +"Match guards as a separate syntax feature are important and necessary when " +"we wish to concisely express more complex ideas than patterns alone would " +"allow." +msgstr "" + +#: src/pattern-matching/match-guards.md:24 +msgid "" +"They are not the same as separate `if` expression inside of the match arm. " +"An `if` expression inside of the branch block (after `=>`) happens after the " +"match arm is selected. Failing the `if` condition inside of that block won't " +"result in other arms of the original `match` expression being considered." +msgstr "" + +#: src/pattern-matching/match-guards.md:26 +msgid "You can use the variables defined in the pattern in your if expression." +msgstr "" + +#: src/pattern-matching/match-guards.md:27 +msgid "" +"The condition defined in the guard applies to every expression in a pattern " +"with an `|`." +msgstr "" + +#: src/exercises/day-1/afternoon.md:1 +msgid "Day 1: Afternoon Exercises" +msgstr "" + +#: src/exercises/day-1/afternoon.md:3 +msgid "We will look at two things:" +msgstr "" + +#: src/exercises/day-1/afternoon.md:5 +msgid "The Luhn algorithm," +msgstr "Luhn-algorithmen," + +#: src/exercises/day-1/afternoon.md:7 +msgid "An exercise on pattern matching." +msgstr "" + +#: src/exercises/day-1/afternoon.md:11 src/exercises/day-2/afternoon.md:7 +#: src/exercises/bare-metal/afternoon.md:7 +#: src/exercises/concurrency/afternoon.md:13 +msgid "" +"After looking at the exercises, you can look at the [solutions](solutions-" +"afternoon.md) provided." +msgstr "" + +#: src/exercises/day-1/luhn.md:3 +msgid "" +"The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is used " +"to validate credit card numbers. The algorithm takes a string as input and " +"does the following to validate the credit card number:" +msgstr "" + +#: src/exercises/day-1/luhn.md:7 +msgid "Ignore all spaces. Reject number with less than two digits." +msgstr "" + +#: src/exercises/day-1/luhn.md:9 +msgid "" +"Moving from **right to left**, double every second digit: for the number " +"`1234`, we double `3` and `1`. For the number `98765`, we double `6` and `8`." +msgstr "" + +#: src/exercises/day-1/luhn.md:12 +msgid "" +"After doubling a digit, sum the digits if the result is greater than 9. So " +"doubling `7` becomes `14` which becomes `1 + 4 = 5`." +msgstr "" + +#: src/exercises/day-1/luhn.md:15 +msgid "Sum all the undoubled and doubled digits." +msgstr "" + +#: src/exercises/day-1/luhn.md:17 +msgid "The credit card number is valid if the sum ends with `0`." +msgstr "" + +#: src/exercises/day-1/luhn.md:19 +msgid "" +"Copy the code below to and implement the " +"function." +msgstr "" + +#: src/exercises/day-1/luhn.md:21 +msgid "" +"Try to solve the problem the \"simple\" way first, using `for` loops and " +"integers. Then, revisit the solution and try to implement it with iterators." +msgstr "" + +#: src/exercises/day-1/luhn.md:25 +msgid "" +"```rust\n" +"// TODO: remove this when you're done with your implementation.\n" +"#![allow(unused_variables, dead_code)]\n" +"\n" +"pub fn luhn(cc_number: &str) -> bool {\n" +" unimplemented!()\n" +"}\n" +"\n" +"#[test]\n" +"fn test_non_digit_cc_number() {\n" +" assert!(!luhn(\"foo\"));\n" +" assert!(!luhn(\"foo 0 0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_empty_cc_number() {\n" +" assert!(!luhn(\"\"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_single_digit_cc_number() {\n" +" assert!(!luhn(\"0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_two_digit_cc_number() {\n" +" assert!(luhn(\" 0 0 \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_valid_cc_number() {\n" +" assert!(luhn(\"4263 9826 4026 9299\"));\n" +" assert!(luhn(\"4539 3195 0343 6467\"));\n" +" assert!(luhn(\"7992 7398 713\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_invalid_cc_number() {\n" +" assert!(!luhn(\"4223 9826 4026 9299\"));\n" +" assert!(!luhn(\"4539 3195 0343 6476\"));\n" +" assert!(!luhn(\"8273 1232 7352 0569\"));\n" +"}\n" +"\n" +"#[allow(dead_code)]\n" +"fn main() {}\n" +"```" +msgstr "" + +#: src/welcome-day-2.md:1 +msgid "Welcome to Day 2" +msgstr "" + +#: src/welcome-day-2.md:3 +msgid "Now that we have seen a fair amount of Rust, we will continue with:" +msgstr "" + +#: src/welcome-day-2.md:5 +msgid "" +"Memory management: stack vs heap, manual memory management, scope-based " +"memory management, and garbage collection." +msgstr "" + +#: src/welcome-day-2.md:8 +msgid "" +"Ownership: move semantics, copying and cloning, borrowing, and lifetimes." +msgstr "" + +#: src/welcome-day-2.md:10 +msgid "Structs and methods." +msgstr "Strenge og iteratorer." + +#: src/welcome-day-2.md:12 +msgid "" +"The Standard Library: `String`, `Option` and `Result`, `Vec`, `HashMap`, " +"`Rc` and `Arc`." +msgstr "" + +#: src/welcome-day-2.md:15 +msgid "Modules: visibility, paths, and filesystem hierarchy." +msgstr "" + #: src/memory-management.md:3 msgid "Traditionally, languages have fallen into two broad categories:" msgstr "" @@ -4254,27 +5570,20 @@ msgid "Safe and correct like Java, but without a garbage collector." msgstr "" #: src/memory-management/rust.md:6 -msgid "" -"Depending on which abstraction (or combination of abstractions) you choose, " -"can be a single unique pointer, reference counted, or atomically reference " -"counted." -msgstr "" - -#: src/memory-management/rust.md:7 msgid "Scope-based like C++, but the compiler enforces full adherence." msgstr "" -#: src/memory-management/rust.md:8 +#: src/memory-management/rust.md:7 msgid "" "A Rust user can choose the right abstraction for the situation, some even " "have no cost at runtime like C." msgstr "" -#: src/memory-management/rust.md:10 +#: src/memory-management/rust.md:9 msgid "Rust achieves this by modeling _ownership_ explicitly." msgstr "" -#: src/memory-management/rust.md:14 +#: src/memory-management/rust.md:13 msgid "" "If asked how at this point, you can mention that in Rust this is usually " "handled by RAII wrapper types such as [Box](https://doc.rust-lang.org/std/" @@ -4285,107 +5594,12 @@ msgid "" "errors in C." msgstr "" -#: src/memory-management/rust.md:16 +#: src/memory-management/rust.md:15 msgid "" "You may be asked about destructors here, the [Drop](https://doc.rust-lang." "org/std/ops/trait.Drop.html) trait is the Rust equivalent." msgstr "" -#: src/memory-management/comparison.md:3 -msgid "Here is a rough comparison of the memory management techniques." -msgstr "" - -#: src/memory-management/comparison.md:5 -msgid "Pros of Different Memory Management Techniques" -msgstr "" - -#: src/memory-management/comparison.md:7 src/memory-management/comparison.md:22 -msgid "Manual like C:" -msgstr "" - -#: src/memory-management/comparison.md:8 src/memory-management/comparison.md:14 -#: src/memory-management/comparison.md:17 -msgid "No runtime overhead." -msgstr "" - -#: src/memory-management/comparison.md:9 src/memory-management/comparison.md:26 -msgid "Automatic like Java:" -msgstr "" - -#: src/memory-management/comparison.md:10 -msgid "Fully automatic." -msgstr "" - -#: src/memory-management/comparison.md:11 -#: src/memory-management/comparison.md:18 -msgid "Safe and correct." -msgstr "" - -#: src/memory-management/comparison.md:12 -#: src/memory-management/comparison.md:29 -msgid "Scope-based like C++:" -msgstr "" - -#: src/memory-management/comparison.md:13 -msgid "Partially automatic." -msgstr "" - -#: src/memory-management/comparison.md:15 -msgid "Compiler-enforced scope-based like Rust:" -msgstr "" - -#: src/memory-management/comparison.md:16 -msgid "Enforced by compiler." -msgstr "" - -#: src/memory-management/comparison.md:20 -msgid "Cons of Different Memory Management Techniques" -msgstr "" - -#: src/memory-management/comparison.md:23 -msgid "Use-after-free." -msgstr "" - -#: src/memory-management/comparison.md:24 -msgid "Double-frees." -msgstr "" - -#: src/memory-management/comparison.md:25 -msgid "Memory leaks." -msgstr "" - -#: src/memory-management/comparison.md:27 -msgid "Garbage collection pauses." -msgstr "" - -#: src/memory-management/comparison.md:28 -msgid "Destructor delays." -msgstr "" - -#: src/memory-management/comparison.md:30 -msgid "Complex, opt-in by programmer (on C++)." -msgstr "" - -#: src/memory-management/comparison.md:31 -msgid "Circular references can lead to memory leaks" -msgstr "" - -#: src/memory-management/comparison.md:32 -msgid "Potential runtime overhead" -msgstr "" - -#: src/memory-management/comparison.md:33 -msgid "Compiler-enforced and scope-based like Rust:" -msgstr "" - -#: src/memory-management/comparison.md:34 -msgid "Some upfront complexity." -msgstr "" - -#: src/memory-management/comparison.md:35 -msgid "Can reject valid programs." -msgstr "" - #: src/ownership.md:3 msgid "" "All variable bindings have a _scope_ where they are valid and it is an error " @@ -4563,8 +5777,8 @@ msgstr "" "```" #: src/ownership/double-free-modern-cpp.md:1 -msgid "Extra Work in Modern C++" -msgstr "Defensiv kopiering i moderne C++" +msgid "Defensive Copies in Modern C++" +msgstr "Defensive kopier i moderne C++" #: src/ownership/double-free-modern-cpp.md:3 msgid "Modern C++ solves this differently:" @@ -4656,6 +5870,28 @@ msgstr "" "`- - - - - - - - - - - - - -'\n" "```" +#: src/ownership/double-free-modern-cpp.md:57 +msgid "" +"C++ has made a slightly different choice than Rust. Because `=` copies data, " +"the string data has to be cloned. Otherwise we would get a double-free when " +"either string goes out of scope." +msgstr "" + +#: src/ownership/double-free-modern-cpp.md:61 +msgid "" +"C++ also has [`std::move`](https://en.cppreference.com/w/cpp/utility/move), " +"which is used to indicate when a value may be moved from. If the example had " +"been `s2 = std::move(s1)`, no heap allocation would take place. After the " +"move, `s1` would be in a valid but unspecified state. Unlike Rust, the " +"programmer is allowed to keep using `s1`." +msgstr "" + +#: src/ownership/double-free-modern-cpp.md:66 +msgid "" +"Unlike Rust, `=` in C++ can run arbitrary code as determined by the type " +"which is being copied or moved." +msgstr "" + #: src/ownership/moves-function-calls.md:3 msgid "" "When you pass a value to a function, the value is assigned to the function " @@ -5132,351 +6368,6 @@ msgid "" "of the struct itself. Those are very advanced use cases." msgstr "" -#: src/exercises/day-1/afternoon.md:1 -msgid "Day 1: Afternoon Exercises" -msgstr "" - -#: src/exercises/day-1/afternoon.md:3 -msgid "We will look at two things:" -msgstr "" - -#: src/exercises/day-1/afternoon.md:5 -msgid "A small book library," -msgstr "" - -#: src/exercises/day-1/afternoon.md:7 -msgid "Iterators and ownership (hard)." -msgstr "" - -#: src/exercises/day-1/afternoon.md:11 src/exercises/day-2/afternoon.md:7 -#: src/exercises/bare-metal/afternoon.md:7 -#: src/exercises/concurrency/afternoon.md:13 -msgid "" -"After looking at the exercises, you can look at the [solutions](solutions-" -"afternoon.md) provided." -msgstr "" - -#: src/exercises/day-1/book-library.md:3 -msgid "" -"We will learn much more about structs and the `Vec` type tomorrow. For " -"now, you just need to know part of its API:" -msgstr "" - -#: src/exercises/day-1/book-library.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut vec = vec![10, 20];\n" -" vec.push(30);\n" -" let midpoint = vec.len() / 2;\n" -" println!(\"middle value: {}\", vec[midpoint]);\n" -" for item in &vec {\n" -" println!(\"item: {item}\");\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/book-library.md:18 -msgid "" -"Use this to model a library's book collection. Copy the code below to " -" and update the types to make it compile:" -msgstr "" - -#: src/exercises/day-1/book-library.md:21 -msgid "" -"```rust,should_panic\n" -"struct Library {\n" -" books: Vec,\n" -"}\n" -"\n" -"struct Book {\n" -" title: String,\n" -" year: u16,\n" -"}\n" -"\n" -"impl Book {\n" -" // This is a constructor, used below.\n" -" fn new(title: &str, year: u16) -> Book {\n" -" Book {\n" -" title: String::from(title),\n" -" year,\n" -" }\n" -" }\n" -"}\n" -"\n" -"// Implement the methods below. Update the `self` parameter to\n" -"// indicate the method's required level of ownership over the object:\n" -"//\n" -"// - `&self` for shared read-only access,\n" -"// - `&mut self` for unique and mutable access,\n" -"// - `self` for unique access by value.\n" -"impl Library {\n" -" fn new() -> Library {\n" -" todo!(\"Initialize and return a `Library` value\")\n" -" }\n" -"\n" -" //fn len(self) -> usize {\n" -" // todo!(\"Return the length of `self.books`\")\n" -" //}\n" -"\n" -" //fn is_empty(self) -> bool {\n" -" // todo!(\"Return `true` if `self.books` is empty\")\n" -" //}\n" -"\n" -" //fn add_book(self, book: Book) {\n" -" // todo!(\"Add a new book to `self.books`\")\n" -" //}\n" -"\n" -" //fn print_books(self) {\n" -" // todo!(\"Iterate over `self.books` and each book's title and " -"year\")\n" -" //}\n" -"\n" -" //fn oldest_book(self) -> Option<&Book> {\n" -" // todo!(\"Return a reference to the oldest book (if any)\")\n" -" //}\n" -"}\n" -"\n" -"// This shows the desired behavior. Uncomment the code below and\n" -"// implement the missing methods. You will need to update the\n" -"// method signatures, including the \"self\" parameter! You may\n" -"// also need to update the variable bindings within main.\n" -"fn main() {\n" -" let library = Library::new();\n" -"\n" -" //println!(\"The library is empty: library.is_empty() -> {}\", library." -"is_empty());\n" -" //\n" -" //library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" -" //library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " -"1865));\n" -" //\n" -" //println!(\"The library is no longer empty: library.is_empty() -> {}\", " -"library.is_empty());\n" -" //\n" -" //\n" -" //library.print_books();\n" -" //\n" -" //match library.oldest_book() {\n" -" // Some(book) => println!(\"The oldest book is {}\", book.title),\n" -" // None => println!(\"The library is empty!\"),\n" -" //}\n" -" //\n" -" //println!(\"The library has {} books\", library.len());\n" -" //library.print_books();\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/book-library.md:102 -msgid "[Solution](solutions-afternoon.md#designing-a-library)" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:3 -msgid "" -"The ownership model of Rust affects many APIs. An example of this is the " -"[`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) and " -"[`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) " -"traits." -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:8 src/bare-metal/no_std.md:28 -msgid "`Iterator`" -msgstr "`Iterator`" - -#: src/exercises/day-1/iterators-and-ownership.md:10 -msgid "" -"Traits are like interfaces: they describe behavior (methods) for a type. The " -"`Iterator` trait simply says that you can call `next` until you get `None` " -"back:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:13 -msgid "" -"```rust\n" -"pub trait Iterator {\n" -" type Item;\n" -" fn next(&mut self) -> Option;\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:20 -msgid "You use this trait like this:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:22 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v: Vec = vec![10, 20, 30];\n" -" let mut iter = v.iter();\n" -"\n" -" println!(\"v[0]: {:?}\", iter.next());\n" -" println!(\"v[1]: {:?}\", iter.next());\n" -" println!(\"v[2]: {:?}\", iter.next());\n" -" println!(\"No more items: {:?}\", iter.next());\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:34 -msgid "What is the type returned by the iterator? Test your answer here:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:36 -msgid "" -"```rust,editable,compile_fail\n" -"fn main() {\n" -" let v: Vec = vec![10, 20, 30];\n" -" let mut iter = v.iter();\n" -"\n" -" let v0: Option<..> = iter.next();\n" -" println!(\"v0: {v0:?}\");\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:46 -msgid "Why is this type used?" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:48 -msgid "`IntoIterator`" -msgstr "`IntoIterator`" - -#: src/exercises/day-1/iterators-and-ownership.md:50 -msgid "" -"The `Iterator` trait tells you how to _iterate_ once you have created an " -"iterator. The related trait `IntoIterator` tells you how to create the " -"iterator:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:53 -msgid "" -"```rust\n" -"pub trait IntoIterator {\n" -" type Item;\n" -" type IntoIter: Iterator;\n" -"\n" -" fn into_iter(self) -> Self::IntoIter;\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:62 -msgid "" -"The syntax here means that every implementation of `IntoIterator` must " -"declare two types:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:65 -msgid "`Item`: the type we iterate over, such as `i8`," -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:66 -msgid "`IntoIter`: the `Iterator` type returned by the `into_iter` method." -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:68 -msgid "" -"Note that `IntoIter` and `Item` are linked: the iterator must have the same " -"`Item` type, which means that it returns `Option`" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:71 -msgid "Like before, what is the type returned by the iterator?" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:73 -msgid "" -"```rust,editable,compile_fail\n" -"fn main() {\n" -" let v: Vec = vec![String::from(\"foo\"), String::" -"from(\"bar\")];\n" -" let mut iter = v.into_iter();\n" -"\n" -" let v0: Option<..> = iter.next();\n" -" println!(\"v0: {v0:?}\");\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:83 -msgid "`for` Loops" -msgstr "`for`\\-løkker" - -#: src/exercises/day-1/iterators-and-ownership.md:85 -msgid "" -"Now that we know both `Iterator` and `IntoIterator`, we can build `for` " -"loops. They call `into_iter()` on an expression and iterates over the " -"resulting iterator:" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:89 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v: Vec = vec![String::from(\"foo\"), String::" -"from(\"bar\")];\n" -"\n" -" for word in &v {\n" -" println!(\"word: {word}\");\n" -" }\n" -"\n" -" for word in v {\n" -" println!(\"word: {word}\");\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:103 -msgid "What is the type of `word` in each loop?" -msgstr "" - -#: src/exercises/day-1/iterators-and-ownership.md:105 -msgid "" -"Experiment with the code above and then consult the documentation for [`impl " -"IntoIterator for &Vec`](https://doc.rust-lang.org/std/vec/struct.Vec." -"html#impl-IntoIterator-for-%26'a+Vec%3CT,+A%3E) and [`impl IntoIterator for " -"Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-IntoIterator-" -"for-Vec%3CT,+A%3E) to check your answers." -msgstr "" - -#: src/welcome-day-2.md:1 -msgid "Welcome to Day 2" -msgstr "" - -#: src/welcome-day-2.md:3 -msgid "Now that we have seen a fair amount of Rust, we will continue with:" -msgstr "" - -#: src/welcome-day-2.md:5 -msgid "Structs, enums, methods." -msgstr "" - -#: src/welcome-day-2.md:7 -msgid "Pattern matching: destructuring enums, structs, and arrays." -msgstr "" - -#: src/welcome-day-2.md:9 -msgid "" -"Control flow constructs: `if`, `if let`, `while`, `while let`, `break`, and " -"`continue`." -msgstr "" - -#: src/welcome-day-2.md:12 -msgid "" -"The Standard Library: `String`, `Option` and `Result`, `Vec`, `HashMap`, " -"`Rc` and `Arc`." -msgstr "" - -#: src/welcome-day-2.md:15 -msgid "Modules: visibility, paths, and filesystem hierarchy." -msgstr "" - #: src/structs.md:3 msgid "Like C and C++, Rust has support for custom structs:" msgstr "" @@ -5508,12 +6399,6 @@ msgid "" "```" msgstr "" -#: src/structs.md:31 src/enums.md:34 src/enums/sizes.md:28 src/methods.md:30 -#: src/methods/example.md:46 src/pattern-matching.md:25 -#: src/pattern-matching/match-guards.md:22 src/control-flow/blocks.md:43 -msgid "Key Points:" -msgstr "" - #: src/structs.md:33 msgid "Structs work like in C or C++." msgstr "" @@ -5737,373 +6622,6 @@ msgid "" "Use `{:#?}` when printing structs to request the `Debug` representation." msgstr "" -#: src/enums.md:3 -msgid "" -"The `enum` keyword allows the creation of a type which has a few different " -"variants:" -msgstr "" - -#: src/enums.md:6 -msgid "" -"```rust,editable\n" -"fn generate_random_number() -> i32 {\n" -" // Implementation based on https://xkcd.com/221/\n" -" 4 // Chosen by fair dice roll. Guaranteed to be random.\n" -"}\n" -"\n" -"#[derive(Debug)]\n" -"enum CoinFlip {\n" -" Heads,\n" -" Tails,\n" -"}\n" -"\n" -"fn flip_coin() -> CoinFlip {\n" -" let random_number = generate_random_number();\n" -" if random_number % 2 == 0 {\n" -" return CoinFlip::Heads;\n" -" } else {\n" -" return CoinFlip::Tails;\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" println!(\"You got: {:?}\", flip_coin());\n" -"}\n" -"```" -msgstr "" - -#: src/enums.md:36 -msgid "Enumerations allow you to collect a set of values under one type" -msgstr "" - -#: src/enums.md:37 -msgid "" -"This page offers an enum type `CoinFlip` with two variants `Heads` and " -"`Tails`. You might note the namespace when using variants." -msgstr "" - -#: src/enums.md:38 -msgid "This might be a good time to compare Structs and Enums:" -msgstr "" - -#: src/enums.md:39 -msgid "" -"In both, you can have a simple version without fields (unit struct) or one " -"with different types of fields (variant payloads). " -msgstr "" - -#: src/enums.md:40 -msgid "In both, associated functions are defined within an `impl` block." -msgstr "" - -#: src/enums.md:41 -msgid "" -"You could even implement the different variants of an enum with separate " -"structs but then they wouldn’t be the same type as they would if they were " -"all defined in an enum. " -msgstr "" - -#: src/enums/variant-payloads.md:3 -msgid "" -"You can define richer enums where the variants carry data. You can then use " -"the `match` statement to extract the data from each variant:" -msgstr "" - -#: src/enums/variant-payloads.md:6 -msgid "" -"```rust,editable\n" -"enum WebEvent {\n" -" PageLoad, // Variant without payload\n" -" KeyPress(char), // Tuple struct variant\n" -" Click { x: i64, y: i64 }, // Full struct variant\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn inspect(event: WebEvent) {\n" -" match event {\n" -" WebEvent::PageLoad => println!(\"page loaded\"),\n" -" WebEvent::KeyPress(c) => println!(\"pressed '{c}'\"),\n" -" WebEvent::Click { x, y } => println!(\"clicked at x={x}, y={y}\"),\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let load = WebEvent::PageLoad;\n" -" let press = WebEvent::KeyPress('x');\n" -" let click = WebEvent::Click { x: 20, y: 80 };\n" -"\n" -" inspect(load);\n" -" inspect(press);\n" -" inspect(click);\n" -"}\n" -"```" -msgstr "" - -#: src/enums/variant-payloads.md:35 -msgid "" -"The values in the enum variants can only be accessed after being pattern " -"matched. The pattern binds references to the fields in the \"match arm\" " -"after the `=>`." -msgstr "" - -#: src/enums/variant-payloads.md:36 -msgid "" -"The expression is matched against the patterns from top to bottom. There is " -"no fall-through like in C or C++." -msgstr "" - -#: src/enums/variant-payloads.md:37 -msgid "" -"The match expression has a value. The value is the last expression in the " -"match arm which was executed." -msgstr "" - -#: src/enums/variant-payloads.md:38 -msgid "" -"Starting from the top we look for what pattern matches the value then run " -"the code following the arrow. Once we find a match, we stop. " -msgstr "" - -#: src/enums/variant-payloads.md:39 -msgid "" -"Demonstrate what happens when the search is inexhaustive. Note the advantage " -"the Rust compiler provides by confirming when all cases are handled. " -msgstr "" - -#: src/enums/variant-payloads.md:40 -msgid "`match` inspects a hidden discriminant field in the `enum`." -msgstr "" - -#: src/enums/variant-payloads.md:41 -msgid "" -"It is possible to retrieve the discriminant by calling `std::mem::" -"discriminant()`" -msgstr "" - -#: src/enums/variant-payloads.md:42 -msgid "" -"This is useful, for example, if implementing `PartialEq` for structs where " -"comparing field values doesn't affect equality." -msgstr "" - -#: src/enums/variant-payloads.md:43 -msgid "" -"`WebEvent::Click { ... }` is not exactly the same as `WebEvent::" -"Click(Click)` with a top level `struct Click { ... }`. The inlined version " -"cannot implement traits, for example." -msgstr "" - -#: src/enums/sizes.md:3 -msgid "" -"Rust enums are packed tightly, taking constraints due to alignment into " -"account:" -msgstr "" - -#: src/enums/sizes.md:5 -msgid "" -"```rust,editable\n" -"use std::any::type_name;\n" -"use std::mem::{align_of, size_of};\n" -"\n" -"fn dbg_size() {\n" -" println!(\"{}: size {} bytes, align: {} bytes\",\n" -" type_name::(), size_of::(), align_of::());\n" -"}\n" -"\n" -"enum Foo {\n" -" A,\n" -" B,\n" -"}\n" -"\n" -"fn main() {\n" -" dbg_size::();\n" -"}\n" -"```" -msgstr "" - -#: src/enums/sizes.md:24 -msgid "" -"See the [Rust Reference](https://doc.rust-lang.org/reference/type-layout." -"html)." -msgstr "" - -#: src/enums/sizes.md:30 -msgid "" -"Internally Rust is using a field (discriminant) to keep track of the enum " -"variant." -msgstr "" - -#: src/enums/sizes.md:32 -msgid "" -"You can control the discriminant if needed (e.g., for compatibility with C):" -msgstr "" - -#: src/enums/sizes.md:34 -msgid "" -"```rust,editable\n" -"#[repr(u32)]\n" -"enum Bar {\n" -" A, // 0\n" -" B = 10000,\n" -" C, // 10001\n" -"}\n" -"\n" -"fn main() {\n" -" println!(\"A: {}\", Bar::A as u32);\n" -" println!(\"B: {}\", Bar::B as u32);\n" -" println!(\"C: {}\", Bar::C as u32);\n" -"}\n" -"```" -msgstr "" - -#: src/enums/sizes.md:49 -msgid "" -"Without `repr`, the discriminant type takes 2 bytes, because 10001 fits 2 " -"bytes." -msgstr "" - -#: src/enums/sizes.md:53 -msgid "Try out other types such as" -msgstr "" - -#: src/enums/sizes.md:55 -msgid "`dbg_size!(bool)`: size 1 bytes, align: 1 bytes," -msgstr "" - -#: src/enums/sizes.md:56 -msgid "" -"`dbg_size!(Option)`: size 1 bytes, align: 1 bytes (niche optimization, " -"see below)," -msgstr "" - -#: src/enums/sizes.md:57 -msgid "`dbg_size!(&i32)`: size 8 bytes, align: 8 bytes (on a 64-bit machine)," -msgstr "" - -#: src/enums/sizes.md:58 -msgid "" -"`dbg_size!(Option<&i32>)`: size 8 bytes, align: 8 bytes (null pointer " -"optimization, see below)." -msgstr "" - -#: src/enums/sizes.md:60 -msgid "" -"Niche optimization: Rust will merge unused bit patterns for the enum " -"discriminant." -msgstr "" - -#: src/enums/sizes.md:63 -msgid "" -"Null pointer optimization: For [some types](https://doc.rust-lang.org/std/" -"option/#representation), Rust guarantees that `size_of::()` equals " -"`size_of::>()`." -msgstr "" - -#: src/enums/sizes.md:67 -msgid "" -"Example code if you want to show how the bitwise representation _may_ look " -"like in practice. It's important to note that the compiler provides no " -"guarantees regarding this representation, therefore this is totally unsafe." -msgstr "" - -#: src/enums/sizes.md:70 -msgid "" -"```rust,editable\n" -"use std::mem::transmute;\n" -"\n" -"macro_rules! dbg_bits {\n" -" ($e:expr, $bit_type:ty) => {\n" -" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, " -"$bit_type>($e));\n" -" };\n" -"}\n" -"\n" -"fn main() {\n" -" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n" -" // representation of types.\n" -" unsafe {\n" -" println!(\"Bitwise representation of bool\");\n" -" dbg_bits!(false, u8);\n" -" dbg_bits!(true, u8);\n" -"\n" -" println!(\"Bitwise representation of Option\");\n" -" dbg_bits!(None::, u8);\n" -" dbg_bits!(Some(false), u8);\n" -" dbg_bits!(Some(true), u8);\n" -"\n" -" println!(\"Bitwise representation of Option>\");\n" -" dbg_bits!(Some(Some(false)), u8);\n" -" dbg_bits!(Some(Some(true)), u8);\n" -" dbg_bits!(Some(None::), u8);\n" -" dbg_bits!(None::>, u8);\n" -"\n" -" println!(\"Bitwise representation of Option<&i32>\");\n" -" dbg_bits!(None::<&i32>, usize);\n" -" dbg_bits!(Some(&0i32), usize);\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/enums/sizes.md:105 -msgid "" -"More complex example if you want to discuss what happens when we chain more " -"than 256 `Option`s together." -msgstr "" - -#: src/enums/sizes.md:107 -msgid "" -"```rust,editable\n" -"#![recursion_limit = \"1000\"]\n" -"\n" -"use std::mem::transmute;\n" -"\n" -"macro_rules! dbg_bits {\n" -" ($e:expr, $bit_type:ty) => {\n" -" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, " -"$bit_type>($e));\n" -" };\n" -"}\n" -"\n" -"// Macro to wrap a value in 2^n Some() where n is the number of \"@\" " -"signs.\n" -"// Increasing the recursion limit is required to evaluate this macro.\n" -"macro_rules! many_options {\n" -" ($value:expr) => { Some($value) };\n" -" ($value:expr, @) => {\n" -" Some(Some($value))\n" -" };\n" -" ($value:expr, @ $($more:tt)+) => {\n" -" many_options!(many_options!($value, $($more)+), $($more)+)\n" -" };\n" -"}\n" -"\n" -"fn main() {\n" -" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n" -" // representation of types.\n" -" unsafe {\n" -" assert_eq!(many_options!(false), Some(false));\n" -" assert_eq!(many_options!(false, @), Some(Some(false)));\n" -" assert_eq!(many_options!(false, @@), " -"Some(Some(Some(Some(false)))));\n" -"\n" -" println!(\"Bitwise representation of a chain of 128 Option's.\");\n" -" dbg_bits!(many_options!(false, @@@@@@@), u8);\n" -" dbg_bits!(many_options!(true, @@@@@@@), u8);\n" -"\n" -" println!(\"Bitwise representation of a chain of 256 Option's.\");\n" -" dbg_bits!(many_options!(false, @@@@@@@@), u16);\n" -" dbg_bits!(many_options!(true, @@@@@@@@), u16);\n" -"\n" -" println!(\"Bitwise representation of a chain of 257 Option's.\");\n" -" dbg_bits!(many_options!(Some(false), @@@@@@@@), u16);\n" -" dbg_bits!(many_options!(Some(true), @@@@@@@@), u16);\n" -" dbg_bits!(many_options!(None::, @@@@@@@@), u16);\n" -" }\n" -"}\n" -"```" -msgstr "" - #: src/methods.md:3 msgid "" "Rust allows you to associate functions with your new types. You do this with " @@ -6310,280 +6828,6 @@ msgid "" "over. We describe vectors in more detail in the afternoon. " msgstr "" -#: src/pattern-matching.md:3 -msgid "" -"The `match` keyword let you match a value against one or more _patterns_. " -"The comparisons are done from top to bottom and the first match wins." -msgstr "" - -#: src/pattern-matching.md:6 -msgid "The patterns can be simple values, similarly to `switch` in C and C++:" -msgstr "" - -#: src/pattern-matching.md:8 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let input = 'x';\n" -"\n" -" match input {\n" -" 'q' => println!(\"Quitting\"),\n" -" 'a' | 's' | 'w' | 'd' => println!(\"Moving around\"),\n" -" '0'..='9' => println!(\"Number input\"),\n" -" _ => println!(\"Something else\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching.md:21 -msgid "The `_` pattern is a wildcard pattern which matches any value." -msgstr "" - -#: src/pattern-matching.md:26 -msgid "" -"You might point out how some specific characters are being used when in a " -"pattern" -msgstr "" - -#: src/pattern-matching.md:27 -msgid "`|` as an `or`" -msgstr "" - -#: src/pattern-matching.md:28 -msgid "`..` can expand as much as it needs to be" -msgstr "" - -#: src/pattern-matching.md:29 -msgid "`1..=5` represents an inclusive range" -msgstr "" - -#: src/pattern-matching.md:30 -msgid "`_` is a wild card" -msgstr "" - -#: src/pattern-matching.md:31 -msgid "" -"It can be useful to show how binding works, by for instance replacing a " -"wildcard character with a variable, or removing the quotes around `q`." -msgstr "" - -#: src/pattern-matching.md:32 -msgid "You can demonstrate matching on a reference." -msgstr "" - -#: src/pattern-matching.md:33 -msgid "" -"This might be a good time to bring up the concept of irrefutable patterns, " -"as the term can show up in error messages." -msgstr "" - -#: src/pattern-matching/destructuring-enums.md:3 -msgid "" -"Patterns can also be used to bind variables to parts of your values. This is " -"how you inspect the structure of your types. Let us start with a simple " -"`enum` type:" -msgstr "" - -#: src/pattern-matching/destructuring-enums.md:6 -msgid "" -"```rust,editable\n" -"enum Result {\n" -" Ok(i32),\n" -" Err(String),\n" -"}\n" -"\n" -"fn divide_in_two(n: i32) -> Result {\n" -" if n % 2 == 0 {\n" -" Result::Ok(n / 2)\n" -" } else {\n" -" Result::Err(format!(\"cannot divide {n} into two equal parts\"))\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let n = 100;\n" -" match divide_in_two(n) {\n" -" Result::Ok(half) => println!(\"{n} divided in two is {half}\"),\n" -" Result::Err(msg) => println!(\"sorry, an error happened: {msg}\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching/destructuring-enums.md:29 -msgid "" -"Here we have used the arms to _destructure_ the `Result` value. In the first " -"arm, `half` is bound to the value inside the `Ok` variant. In the second " -"arm, `msg` is bound to the error message." -msgstr "" - -#: src/pattern-matching/destructuring-enums.md:36 -msgid "" -"The `if`/`else` expression is returning an enum that is later unpacked with " -"a `match`." -msgstr "" - -#: src/pattern-matching/destructuring-enums.md:37 -msgid "" -"You can try adding a third variant to the enum definition and displaying the " -"errors when running the code. Point out the places where your code is now " -"inexhaustive and how the compiler tries to give you hints." -msgstr "" - -#: src/pattern-matching/destructuring-structs.md:3 -msgid "You can also destructure `structs`:" -msgstr "" - -#: src/pattern-matching/destructuring-structs.md:5 -msgid "" -"```rust,editable\n" -"struct Foo {\n" -" x: (u32, u32),\n" -" y: u32,\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let foo = Foo { x: (1, 2), y: 3 };\n" -" match foo {\n" -" Foo { x: (1, b), y } => println!(\"x.0 = 1, b = {b}, y = {y}\"),\n" -" Foo { y: 2, x: i } => println!(\"y = 2, x = {i:?}\"),\n" -" Foo { y, .. } => println!(\"y = {y}, other fields were " -"ignored\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching/destructuring-structs.md:23 -msgid "Change the literal values in `foo` to match with the other patterns." -msgstr "" - -#: src/pattern-matching/destructuring-structs.md:24 -msgid "Add a new field to `Foo` and make changes to the pattern as needed." -msgstr "" - -#: src/pattern-matching/destructuring-structs.md:25 -msgid "" -"The distinction between a capture and a constant expression can be hard to " -"spot. Try changing the `2` in the second arm to a variable, and see that it " -"subtly doesn't work. Change it to a `const` and see it working again." -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:3 -msgid "" -"You can destructure arrays, tuples, and slices by matching on their elements:" -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:5 -msgid "" -"```rust,editable\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let triple = [0, -2, 3];\n" -" println!(\"Tell me about {triple:?}\");\n" -" match triple {\n" -" [0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" -" [1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" -" _ => println!(\"All elements were ignored\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:21 -msgid "" -"Destructuring of slices of unknown length also works with patterns of fixed " -"length." -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:24 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" inspect(&[0, -2, 3]);\n" -" inspect(&[0, -2, 3, 4]);\n" -"}\n" -"\n" -"#[rustfmt::skip]\n" -"fn inspect(slice: &[i32]) {\n" -" println!(\"Tell me about {slice:?}\");\n" -" match slice {\n" -" &[0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n" -" &[1, ..] => println!(\"First is 1 and the rest were ignored\"),\n" -" _ => println!(\"All elements were ignored\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:41 -msgid "Create a new pattern using `_` to represent an element. " -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:42 -msgid "Add more values to the array." -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:43 -msgid "" -"Point out that how `..` will expand to account for different number of " -"elements." -msgstr "" - -#: src/pattern-matching/destructuring-arrays.md:44 -msgid "Show matching against the tail with patterns `[.., b]` and `[a@..,b]`" -msgstr "" - -#: src/pattern-matching/match-guards.md:3 -msgid "" -"When matching, you can add a _guard_ to a pattern. This is an arbitrary " -"Boolean expression which will be executed if the pattern matches:" -msgstr "" - -#: src/pattern-matching/match-guards.md:6 -msgid "" -"```rust,editable\n" -"#[rustfmt::skip]\n" -"fn main() {\n" -" let pair = (2, -2);\n" -" println!(\"Tell me about {pair:?}\");\n" -" match pair {\n" -" (x, y) if x == y => println!(\"These are twins\"),\n" -" (x, y) if x + y == 0 => println!(\"Antimatter, kaboom!\"),\n" -" (x, _) if x % 2 == 1 => println!(\"The first one is odd\"),\n" -" _ => println!(\"No correlation...\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/pattern-matching/match-guards.md:23 -msgid "" -"Match guards as a separate syntax feature are important and necessary when " -"we wish to concisely express more complex ideas than patterns alone would " -"allow." -msgstr "" - -#: src/pattern-matching/match-guards.md:24 -msgid "" -"They are not the same as separate `if` expression inside of the match arm. " -"An `if` expression inside of the branch block (after `=>`) happens after the " -"match arm is selected. Failing the `if` condition inside of that block won't " -"result in other arms of the original `match` expression being considered." -msgstr "" - -#: src/pattern-matching/match-guards.md:26 -msgid "You can use the variables defined in the pattern in your if expression." -msgstr "" - -#: src/pattern-matching/match-guards.md:27 -msgid "" -"The condition defined in the guard applies to every expression in a pattern " -"with an `|`." -msgstr "" - #: src/exercises/day-2/morning.md:1 msgid "Day 2: Morning Exercises" msgstr "Dag 2: formiddagsøvelser" @@ -6593,11 +6837,128 @@ msgid "We will look at implementing methods in two contexts:" msgstr "" #: src/exercises/day-2/morning.md:5 -msgid "Simple struct which tracks health statistics." +msgid "Storing books and querying the collection" msgstr "" #: src/exercises/day-2/morning.md:7 -msgid "Multiple structs and enums for a drawing library." +msgid "Keeping track of health statistics for patients" +msgstr "" + +#: src/exercises/day-2/book-library.md:3 +msgid "" +"We will learn much more about structs and the `Vec` type tomorrow. For " +"now, you just need to know part of its API:" +msgstr "" + +#: src/exercises/day-2/book-library.md:6 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let mut vec = vec![10, 20];\n" +" vec.push(30);\n" +" let midpoint = vec.len() / 2;\n" +" println!(\"middle value: {}\", vec[midpoint]);\n" +" for item in &vec {\n" +" println!(\"item: {item}\");\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/book-library.md:18 +msgid "" +"Use this to model a library's book collection. Copy the code below to " +" and update the types to make it compile:" +msgstr "" + +#: src/exercises/day-2/book-library.md:21 +msgid "" +"```rust,should_panic\n" +"struct Library {\n" +" books: Vec,\n" +"}\n" +"\n" +"struct Book {\n" +" title: String,\n" +" year: u16,\n" +"}\n" +"\n" +"impl Book {\n" +" // This is a constructor, used below.\n" +" fn new(title: &str, year: u16) -> Book {\n" +" Book {\n" +" title: String::from(title),\n" +" year,\n" +" }\n" +" }\n" +"}\n" +"\n" +"// Implement the methods below. Update the `self` parameter to\n" +"// indicate the method's required level of ownership over the object:\n" +"//\n" +"// - `&self` for shared read-only access,\n" +"// - `&mut self` for unique and mutable access,\n" +"// - `self` for unique access by value.\n" +"impl Library {\n" +" fn new() -> Library {\n" +" todo!(\"Initialize and return a `Library` value\")\n" +" }\n" +"\n" +" //fn len(self) -> usize {\n" +" // todo!(\"Return the length of `self.books`\")\n" +" //}\n" +"\n" +" //fn is_empty(self) -> bool {\n" +" // todo!(\"Return `true` if `self.books` is empty\")\n" +" //}\n" +"\n" +" //fn add_book(self, book: Book) {\n" +" // todo!(\"Add a new book to `self.books`\")\n" +" //}\n" +"\n" +" //fn print_books(self) {\n" +" // todo!(\"Iterate over `self.books` and print each book's title and " +"year\")\n" +" //}\n" +"\n" +" //fn oldest_book(self) -> Option<&Book> {\n" +" // todo!(\"Return a reference to the oldest book (if any)\")\n" +" //}\n" +"}\n" +"\n" +"// This shows the desired behavior. Uncomment the code below and\n" +"// implement the missing methods. You will need to update the\n" +"// method signatures, including the \"self\" parameter! You may\n" +"// also need to update the variable bindings within main.\n" +"fn main() {\n" +" let library = Library::new();\n" +"\n" +" //println!(\"The library is empty: library.is_empty() -> {}\", library." +"is_empty());\n" +" //\n" +" //library.add_book(Book::new(\"Lord of the Rings\", 1954));\n" +" //library.add_book(Book::new(\"Alice's Adventures in Wonderland\", " +"1865));\n" +" //\n" +" //println!(\"The library is no longer empty: library.is_empty() -> {}\", " +"library.is_empty());\n" +" //\n" +" //\n" +" //library.print_books();\n" +" //\n" +" //match library.oldest_book() {\n" +" // Some(book) => println!(\"The oldest book is {}\", book.title),\n" +" // None => println!(\"The library is empty!\"),\n" +" //}\n" +" //\n" +" //println!(\"The library has {} books\", library.len());\n" +" //library.print_books();\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/book-library.md:102 +msgid "[Solution](solutions-afternoon.md#designing-a-library)" msgstr "" #: src/exercises/day-2/health-statistics.md:3 @@ -6722,625 +7083,6 @@ msgid "" "```" msgstr "" -#: src/exercises/day-2/points-polygons.md:1 -msgid "Polygon Struct" -msgstr "" - -#: src/exercises/day-2/points-polygons.md:3 -msgid "" -"We will create a `Polygon` struct which contain some points. Copy the code " -"below to and fill in the missing methods to " -"make the tests pass:" -msgstr "" - -#: src/exercises/day-2/points-polygons.md:7 -msgid "" -"```rust\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub struct Point {\n" -" // add fields\n" -"}\n" -"\n" -"impl Point {\n" -" // add methods\n" -"}\n" -"\n" -"pub struct Polygon {\n" -" // add fields\n" -"}\n" -"\n" -"impl Polygon {\n" -" // add methods\n" -"}\n" -"\n" -"pub struct Circle {\n" -" // add fields\n" -"}\n" -"\n" -"impl Circle {\n" -" // add methods\n" -"}\n" -"\n" -"pub enum Shape {\n" -" Polygon(Polygon),\n" -" Circle(Circle),\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -"\n" -" fn round_two_digits(x: f64) -> f64 {\n" -" (x * 100.0).round() / 100.0\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_magnitude() {\n" -" let p1 = Point::new(12, 13);\n" -" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_dist() {\n" -" let p1 = Point::new(10, 10);\n" -" let p2 = Point::new(14, 13);\n" -" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_add() {\n" -" let p1 = Point::new(16, 16);\n" -" let p2 = p1 + Point::new(-4, 3);\n" -" assert_eq!(p2, Point::new(12, 19));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_left_most_point() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -" assert_eq!(poly.left_most_point(), Some(p1));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_iter() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -"\n" -" let points = poly.iter().cloned().collect::>();\n" -" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_shape_perimeters() {\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(Point::new(12, 13));\n" -" poly.add_point(Point::new(17, 11));\n" -" poly.add_point(Point::new(16, 16));\n" -" let shapes = vec![\n" -" Shape::from(poly),\n" -" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" -" ];\n" -" let perimeters = shapes\n" -" .iter()\n" -" .map(Shape::perimeter)\n" -" .map(round_two_digits)\n" -" .collect::>();\n" -" assert_eq!(perimeters, vec![15.48, 31.42]);\n" -" }\n" -"}\n" -"\n" -"#[allow(dead_code)]\n" -"fn main() {}\n" -"```" -msgstr "" - -#: src/exercises/day-2/points-polygons.md:117 -msgid "" -"Since the method signatures are missing from the problem statements, the key " -"part of the exercise is to specify those correctly. You don't have to modify " -"the tests." -msgstr "" - -#: src/exercises/day-2/points-polygons.md:120 -msgid "Other interesting parts of the exercise:" -msgstr "" - -#: src/exercises/day-2/points-polygons.md:122 -msgid "" -"Derive a `Copy` trait for some structs, as in tests the methods sometimes " -"don't borrow their arguments." -msgstr "" - -#: src/exercises/day-2/points-polygons.md:123 -msgid "" -"Discover that `Add` trait must be implemented for two objects to be addable " -"via \"+\". Note that we do not discuss generics until Day 3." -msgstr "" - -#: src/control-flow.md:3 -msgid "" -"As we have seen, `if` is an expression in Rust. It is used to conditionally " -"evaluate one of two blocks, but the blocks can have a value which then " -"becomes the value of the `if` expression. Other control flow expressions " -"work similarly in Rust." -msgstr "" - -#: src/control-flow/blocks.md:3 -msgid "" -"A block in Rust contains a sequence of expressions. Each block has a value " -"and a type, which are those of the last expression of the block:" -msgstr "" - -#: src/control-flow/blocks.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let x = {\n" -" let y = 10;\n" -" println!(\"y: {y}\");\n" -" let z = {\n" -" let w = {\n" -" 3 + 4\n" -" };\n" -" println!(\"w: {w}\");\n" -" y * w\n" -" };\n" -" println!(\"z: {z}\");\n" -" z - y\n" -" };\n" -" println!(\"x: {x}\");\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/blocks.md:26 -msgid "" -"If the last expression ends with `;`, then the resulting value and type is " -"`()`." -msgstr "" - -#: src/control-flow/blocks.md:28 -msgid "" -"The same rule is used for functions: the value of the function body is the " -"return value:" -msgstr "" - -#: src/control-flow/blocks.md:31 -msgid "" -"```rust,editable\n" -"fn double(x: i32) -> i32 {\n" -" x + x\n" -"}\n" -"\n" -"fn main() {\n" -" println!(\"doubled: {}\", double(7));\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/blocks.md:44 -msgid "" -"The point of this slide is to show that blocks have a type and value in " -"Rust. " -msgstr "" - -#: src/control-flow/blocks.md:45 -msgid "" -"You can show how the value of the block changes by changing the last line in " -"the block. For instance, adding/removing a semicolon or using a `return`." -msgstr "" - -#: src/control-flow/if-expressions.md:1 -msgid "`if` expressions" -msgstr "" - -#: src/control-flow/if-expressions.md:3 -msgid "" -"You use [`if` expressions](https://doc.rust-lang.org/reference/expressions/" -"if-expr.html#if-expressions) exactly like `if` statements in other languages:" -msgstr "" - -#: src/control-flow/if-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut x = 10;\n" -" if x % 2 == 0 {\n" -" x = x / 2;\n" -" } else {\n" -" x = 3 * x + 1;\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/if-expressions.md:18 -msgid "" -"In addition, you can use `if` as an expression. The last expression of each " -"block becomes the value of the `if` expression:" -msgstr "" - -#: src/control-flow/if-expressions.md:22 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut x = 10;\n" -" x = if x % 2 == 0 {\n" -" x / 2\n" -" } else {\n" -" 3 * x + 1\n" -" };\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/if-expressions.md:35 -msgid "" -"Because `if` is an expression and must have a particular type, both of its " -"branch blocks must have the same type. Consider showing what happens if you " -"add `;` after `x / 2` in the second example." -msgstr "" - -#: src/control-flow/if-let-expressions.md:1 -msgid "`if let` expressions" -msgstr "" - -#: src/control-flow/if-let-expressions.md:3 -msgid "" -"The [`if let` expression](https://doc.rust-lang.org/reference/expressions/if-" -"expr.html#if-let-expressions) lets you execute different code depending on " -"whether a value matches a pattern:" -msgstr "" - -#: src/control-flow/if-let-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let arg = std::env::args().next();\n" -" if let Some(value) = arg {\n" -" println!(\"Program name: {value}\");\n" -" } else {\n" -" println!(\"Missing name?\");\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/if-let-expressions.md:18 -#: src/control-flow/while-let-expressions.md:21 -#: src/control-flow/match-expressions.md:23 -msgid "" -"See [pattern matching](../pattern-matching.md) for more details on patterns " -"in Rust." -msgstr "" - -#: src/control-flow/if-let-expressions.md:23 -msgid "" -"Unlike `match`, `if let` does not have to cover all branches. This can make " -"it more concise than `match`." -msgstr "" - -#: src/control-flow/if-let-expressions.md:24 -msgid "A common usage is handling `Some` values when working with `Option`." -msgstr "" - -#: src/control-flow/if-let-expressions.md:25 -msgid "" -"Unlike `match`, `if let` does not support guard clauses for pattern matching." -msgstr "" - -#: src/control-flow/if-let-expressions.md:26 -msgid "" -"Since 1.65, a similar [let-else](https://doc.rust-lang.org/rust-by-example/" -"flow_control/let_else.html) construct allows to do a destructuring " -"assignment, or if it fails, execute a block which is required to abort " -"normal control flow (with `panic`/`return`/`break`/`continue`):" -msgstr "" - -#: src/control-flow/if-let-expressions.md:28 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" println!(\"{:?}\", second_word_to_upper(\"foo bar\"));\n" -"}\n" -" \n" -"fn second_word_to_upper(s: &str) -> Option {\n" -" let mut it = s.split(' ');\n" -" let (Some(_), Some(item)) = (it.next(), it.next()) else {\n" -" return None;\n" -" };\n" -" Some(item.to_uppercase())\n" -"}\n" -"\n" -"```" -msgstr "" - -#: src/control-flow/while-expressions.md:1 -msgid "`while` loops" -msgstr "" - -#: src/control-flow/while-expressions.md:3 -msgid "" -"The [`while` keyword](https://doc.rust-lang.org/reference/expressions/loop-" -"expr.html#predicate-loops) works very similar to other languages:" -msgstr "" - -#: src/control-flow/while-expressions.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut x = 10;\n" -" while x != 1 {\n" -" x = if x % 2 == 0 {\n" -" x / 2\n" -" } else {\n" -" 3 * x + 1\n" -" };\n" -" }\n" -" println!(\"Final x: {x}\");\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/while-let-expressions.md:1 -msgid "`while let` loops" -msgstr "" - -#: src/control-flow/while-let-expressions.md:3 -msgid "" -"Like with `if let`, there is a [`while let`](https://doc.rust-lang.org/" -"reference/expressions/loop-expr.html#predicate-pattern-loops) variant which " -"repeatedly tests a value against a pattern:" -msgstr "" - -#: src/control-flow/while-let-expressions.md:6 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v = vec![10, 20, 30];\n" -" let mut iter = v.into_iter();\n" -"\n" -" while let Some(x) = iter.next() {\n" -" println!(\"x: {x}\");\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/while-let-expressions.md:17 -msgid "" -"Here the iterator returned by `v.into_iter()` will return a `Option` on " -"every call to `next()`. It returns `Some(x)` until it is done, after which " -"it will return `None`. The `while let` lets us keep iterating through all " -"items." -msgstr "" - -#: src/control-flow/while-let-expressions.md:26 -msgid "" -"Point out that the `while let` loop will keep going as long as the value " -"matches the pattern." -msgstr "" - -#: src/control-flow/while-let-expressions.md:27 -msgid "" -"You could rewrite the `while let` loop as an infinite loop with an if " -"statement that breaks when there is no value to unwrap for `iter.next()`. " -"The `while let` provides syntactic sugar for the above scenario." -msgstr "" - -#: src/control-flow/for-expressions.md:1 -msgid "`for` loops" -msgstr "" - -#: src/control-flow/for-expressions.md:3 -msgid "" -"The [`for` loop](https://doc.rust-lang.org/std/keyword.for.html) is closely " -"related to the [`while let` loop](while-let-expressions.md). It will " -"automatically call `into_iter()` on the expression and then iterate over it:" -msgstr "" - -#: src/control-flow/for-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v = vec![10, 20, 30];\n" -"\n" -" for x in v {\n" -" println!(\"x: {x}\");\n" -" }\n" -" \n" -" for i in (0..10).step_by(2) {\n" -" println!(\"i: {i}\");\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/for-expressions.md:21 -msgid "You can use `break` and `continue` here as usual." -msgstr "" - -#: src/control-flow/for-expressions.md:25 -msgid "Index iteration is not a special syntax in Rust for just that case." -msgstr "" - -#: src/control-flow/for-expressions.md:26 -msgid "`(0..10)` is a range that implements an `Iterator` trait. " -msgstr "" - -#: src/control-flow/for-expressions.md:27 -msgid "" -"`step_by` is a method that returns another `Iterator` that skips every other " -"element. " -msgstr "" - -#: src/control-flow/for-expressions.md:28 -msgid "" -"Modify the elements in the vector and explain the compiler errors. Change " -"vector `v` to be mutable and the for loop to `for x in v.iter_mut()`." -msgstr "" - -#: src/control-flow/loop-expressions.md:1 -msgid "`loop` expressions" -msgstr "" - -#: src/control-flow/loop-expressions.md:3 -msgid "" -"Finally, there is a [`loop` keyword](https://doc.rust-lang.org/reference/" -"expressions/loop-expr.html#infinite-loops) which creates an endless loop." -msgstr "" - -#: src/control-flow/loop-expressions.md:6 -msgid "Here you must either `break` or `return` to stop the loop:" -msgstr "" - -#: src/control-flow/loop-expressions.md:8 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let mut x = 10;\n" -" loop {\n" -" x = if x % 2 == 0 {\n" -" x / 2\n" -" } else {\n" -" 3 * x + 1\n" -" };\n" -" if x == 1 {\n" -" break;\n" -" }\n" -" }\n" -" println!(\"Final x: {x}\");\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/loop-expressions.md:27 -msgid "Break the `loop` with a value (e.g. `break 8`) and print it out." -msgstr "" - -#: src/control-flow/loop-expressions.md:28 -msgid "" -"Note that `loop` is the only looping construct which returns a non-trivial " -"value. This is because it's guaranteed to be entered at least once (unlike " -"`while` and `for` loops)." -msgstr "" - -#: src/control-flow/match-expressions.md:1 -msgid "`match` expressions" -msgstr "" - -#: src/control-flow/match-expressions.md:3 -msgid "" -"The [`match` keyword](https://doc.rust-lang.org/reference/expressions/match-" -"expr.html) is used to match a value against one or more patterns. In that " -"sense, it works like a series of `if let` expressions:" -msgstr "" - -#: src/control-flow/match-expressions.md:7 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" match std::env::args().next().as_deref() {\n" -" Some(\"cat\") => println!(\"Will do cat things\"),\n" -" Some(\"ls\") => println!(\"Will ls some files\"),\n" -" Some(\"mv\") => println!(\"Let's move some files\"),\n" -" Some(\"rm\") => println!(\"Uh, dangerous!\"),\n" -" None => println!(\"Hmm, no program name?\"),\n" -" _ => println!(\"Unknown program name!\"),\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/match-expressions.md:20 -msgid "" -"Like `if let`, each match arm must have the same type. The type is the last " -"expression of the block, if any. In the example above, the type is `()`." -msgstr "" - -#: src/control-flow/match-expressions.md:28 -msgid "Save the match expression to a variable and print it out." -msgstr "" - -#: src/control-flow/match-expressions.md:29 -msgid "Remove `.as_deref()` and explain the error." -msgstr "" - -#: src/control-flow/match-expressions.md:30 -msgid "" -"`std::env::args().next()` returns an `Option`, but we cannot match " -"against `String`." -msgstr "" - -#: src/control-flow/match-expressions.md:31 -msgid "" -"`as_deref()` transforms an `Option` to `Option<&T::Target>`. In our case, " -"this turns `Option` into `Option<&str>`." -msgstr "" - -#: src/control-flow/match-expressions.md:32 -msgid "" -"We can now use pattern matching to match against the `&str` inside `Option`." -msgstr "" - -#: src/control-flow/break-continue.md:1 -msgid "`break` and `continue`" -msgstr "" - -#: src/control-flow/break-continue.md:3 -msgid "" -"If you want to exit a loop early, use [`break`](https://doc.rust-lang.org/" -"reference/expressions/loop-expr.html#break-expressions)," -msgstr "" - -#: src/control-flow/break-continue.md:4 -msgid "" -"If you want to immediately start the next iteration use [`continue`](https://" -"doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)." -msgstr "" - -#: src/control-flow/break-continue.md:7 -msgid "" -"Both `continue` and `break` can optionally take a label argument which is " -"used to break out of nested loops:" -msgstr "" - -#: src/control-flow/break-continue.md:10 -msgid "" -"```rust,editable\n" -"fn main() {\n" -" let v = vec![10, 20, 30];\n" -" let mut iter = v.into_iter();\n" -" 'outer: while let Some(x) = iter.next() {\n" -" println!(\"x: {x}\");\n" -" let mut i = 0;\n" -" while i < x {\n" -" println!(\"x: {x}, i: {i}\");\n" -" i += 1;\n" -" if i == 3 {\n" -" break 'outer;\n" -" }\n" -" }\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/control-flow/break-continue.md:28 -msgid "" -"In this case we break the outer loop after 3 iterations of the inner loop." -msgstr "" - #: src/std.md:3 msgid "" "Rust comes with a standard library which helps establish a set of common " @@ -8387,101 +8129,178 @@ msgstr "" msgid "The exercises for this afternoon will focus on strings and iterators." msgstr "" -#: src/exercises/day-2/luhn.md:3 +#: src/exercises/day-2/iterators-and-ownership.md:3 msgid "" -"The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is used " -"to validate credit card numbers. The algorithm takes a string as input and " -"does the following to validate the credit card number:" +"The ownership model of Rust affects many APIs. An example of this is the " +"[`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) and " +"[`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) " +"traits." msgstr "" -#: src/exercises/day-2/luhn.md:7 -msgid "Ignore all spaces. Reject number with less than two digits." -msgstr "" +#: src/exercises/day-2/iterators-and-ownership.md:8 src/bare-metal/no_std.md:28 +msgid "`Iterator`" +msgstr "`Iterator`" -#: src/exercises/day-2/luhn.md:9 +#: src/exercises/day-2/iterators-and-ownership.md:10 msgid "" -"Moving from **right to left**, double every second digit: for the number " -"`1234`, we double `3` and `1`. For the number `98765`, we double `6` and `8`." +"Traits are like interfaces: they describe behavior (methods) for a type. The " +"`Iterator` trait simply says that you can call `next` until you get `None` " +"back:" msgstr "" -#: src/exercises/day-2/luhn.md:12 -msgid "" -"After doubling a digit, sum the digits. So doubling `7` becomes `14` which " -"becomes `5`." -msgstr "" - -#: src/exercises/day-2/luhn.md:15 -msgid "Sum all the undoubled and doubled digits." -msgstr "" - -#: src/exercises/day-2/luhn.md:17 -msgid "The credit card number is valid if the sum ends with `0`." -msgstr "" - -#: src/exercises/day-2/luhn.md:19 -msgid "" -"Copy the code below to and implement the " -"function." -msgstr "" - -#: src/exercises/day-2/luhn.md:21 -msgid "" -"Try to solve the problem the \"simple\" way first, using `for` loops and " -"integers. Then, revisit the solution and try to implement it with iterators." -msgstr "" - -#: src/exercises/day-2/luhn.md:25 +#: src/exercises/day-2/iterators-and-ownership.md:13 msgid "" "```rust\n" -"// TODO: remove this when you're done with your implementation.\n" -"#![allow(unused_variables, dead_code)]\n" -"\n" -"pub fn luhn(cc_number: &str) -> bool {\n" -" unimplemented!()\n" +"pub trait Iterator {\n" +" type Item;\n" +" fn next(&mut self) -> Option;\n" "}\n" -"\n" -"#[test]\n" -"fn test_non_digit_cc_number() {\n" -" assert!(!luhn(\"foo\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty_cc_number() {\n" -" assert!(!luhn(\"\"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_digit_cc_number() {\n" -" assert!(!luhn(\"0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_two_digit_cc_number() {\n" -" assert!(luhn(\" 0 0 \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_valid_cc_number() {\n" -" assert!(luhn(\"4263 9826 4026 9299\"));\n" -" assert!(luhn(\"4539 3195 0343 6467\"));\n" -" assert!(luhn(\"7992 7398 713\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_invalid_cc_number() {\n" -" assert!(!luhn(\"4223 9826 4026 9299\"));\n" -" assert!(!luhn(\"4539 3195 0343 6476\"));\n" -" assert!(!luhn(\"8273 1232 7352 0569\"));\n" -"}\n" -"\n" -"#[allow(dead_code)]\n" -"fn main() {}\n" "```" msgstr "" +#: src/exercises/day-2/iterators-and-ownership.md:20 +msgid "You use this trait like this:" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:22 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let v: Vec = vec![10, 20, 30];\n" +" let mut iter = v.iter();\n" +"\n" +" println!(\"v[0]: {:?}\", iter.next());\n" +" println!(\"v[1]: {:?}\", iter.next());\n" +" println!(\"v[2]: {:?}\", iter.next());\n" +" println!(\"No more items: {:?}\", iter.next());\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:34 +msgid "What is the type returned by the iterator? Test your answer here:" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:36 +msgid "" +"```rust,editable,compile_fail\n" +"fn main() {\n" +" let v: Vec = vec![10, 20, 30];\n" +" let mut iter = v.iter();\n" +"\n" +" let v0: Option<..> = iter.next();\n" +" println!(\"v0: {v0:?}\");\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:46 +msgid "Why is this type used?" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:48 +msgid "`IntoIterator`" +msgstr "`IntoIterator`" + +#: src/exercises/day-2/iterators-and-ownership.md:50 +msgid "" +"The `Iterator` trait tells you how to _iterate_ once you have created an " +"iterator. The related trait `IntoIterator` tells you how to create the " +"iterator:" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:53 +msgid "" +"```rust\n" +"pub trait IntoIterator {\n" +" type Item;\n" +" type IntoIter: Iterator;\n" +"\n" +" fn into_iter(self) -> Self::IntoIter;\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:62 +msgid "" +"The syntax here means that every implementation of `IntoIterator` must " +"declare two types:" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:65 +msgid "`Item`: the type we iterate over, such as `i8`," +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:66 +msgid "`IntoIter`: the `Iterator` type returned by the `into_iter` method." +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:68 +msgid "" +"Note that `IntoIter` and `Item` are linked: the iterator must have the same " +"`Item` type, which means that it returns `Option`" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:71 +msgid "Like before, what is the type returned by the iterator?" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:73 +msgid "" +"```rust,editable,compile_fail\n" +"fn main() {\n" +" let v: Vec = vec![String::from(\"foo\"), String::" +"from(\"bar\")];\n" +" let mut iter = v.into_iter();\n" +"\n" +" let v0: Option<..> = iter.next();\n" +" println!(\"v0: {v0:?}\");\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:83 +msgid "`for` Loops" +msgstr "`for`\\-løkker" + +#: src/exercises/day-2/iterators-and-ownership.md:85 +msgid "" +"Now that we know both `Iterator` and `IntoIterator`, we can build `for` " +"loops. They call `into_iter()` on an expression and iterates over the " +"resulting iterator:" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:89 +msgid "" +"```rust,editable\n" +"fn main() {\n" +" let v: Vec = vec![String::from(\"foo\"), String::" +"from(\"bar\")];\n" +"\n" +" for word in &v {\n" +" println!(\"word: {word}\");\n" +" }\n" +"\n" +" for word in v {\n" +" println!(\"word: {word}\");\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:103 +msgid "What is the type of `word` in each loop?" +msgstr "" + +#: src/exercises/day-2/iterators-and-ownership.md:105 +msgid "" +"Experiment with the code above and then consult the documentation for [`impl " +"IntoIterator for &Vec`](https://doc.rust-lang.org/std/vec/struct.Vec." +"html#impl-IntoIterator-for-%26'a+Vec%3CT,+A%3E) and [`impl IntoIterator for " +"Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-IntoIterator-" +"for-Vec%3CT,+A%3E) to check your answers." +msgstr "" + #: src/exercises/day-2/strings-iterators.md:3 msgid "" "In this exercise, you are implementing a routing component of a web server. " @@ -9736,7 +9555,13 @@ msgid "Day 3: Morning Exercises" msgstr "Dag 3: Formiddagsøvelser" #: src/exercises/day-3/morning.md:3 -msgid "We will design a classical GUI library traits and trait objects." +msgid "We will design a classical GUI library using traits and trait objects." +msgstr "" + +#: src/exercises/day-3/morning.md:5 +msgid "" +"We will also look at enum dispatch with an exercise involving points and " +"polygons." msgstr "" #: src/exercises/day-3/simple-gui.md:3 @@ -9945,6 +9770,151 @@ msgid "" "```" msgstr "" +#: src/exercises/day-3/points-polygons.md:1 +msgid "Polygon Struct" +msgstr "" + +#: src/exercises/day-3/points-polygons.md:3 +msgid "" +"We will create a `Polygon` struct which contain some points. Copy the code " +"below to and fill in the missing methods to " +"make the tests pass:" +msgstr "" + +#: src/exercises/day-3/points-polygons.md:7 +msgid "" +"```rust\n" +"// TODO: remove this when you're done with your implementation.\n" +"#![allow(unused_variables, dead_code)]\n" +"\n" +"pub struct Point {\n" +" // add fields\n" +"}\n" +"\n" +"impl Point {\n" +" // add methods\n" +"}\n" +"\n" +"pub struct Polygon {\n" +" // add fields\n" +"}\n" +"\n" +"impl Polygon {\n" +" // add methods\n" +"}\n" +"\n" +"pub struct Circle {\n" +" // add fields\n" +"}\n" +"\n" +"impl Circle {\n" +" // add methods\n" +"}\n" +"\n" +"pub enum Shape {\n" +" Polygon(Polygon),\n" +" Circle(Circle),\n" +"}\n" +"\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::*;\n" +"\n" +" fn round_two_digits(x: f64) -> f64 {\n" +" (x * 100.0).round() / 100.0\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_magnitude() {\n" +" let p1 = Point::new(12, 13);\n" +" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_dist() {\n" +" let p1 = Point::new(10, 10);\n" +" let p2 = Point::new(14, 13);\n" +" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_add() {\n" +" let p1 = Point::new(16, 16);\n" +" let p2 = p1 + Point::new(-4, 3);\n" +" assert_eq!(p2, Point::new(12, 19));\n" +" }\n" +"\n" +" #[test]\n" +" fn test_polygon_left_most_point() {\n" +" let p1 = Point::new(12, 13);\n" +" let p2 = Point::new(16, 16);\n" +"\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(p1);\n" +" poly.add_point(p2);\n" +" assert_eq!(poly.left_most_point(), Some(p1));\n" +" }\n" +"\n" +" #[test]\n" +" fn test_polygon_iter() {\n" +" let p1 = Point::new(12, 13);\n" +" let p2 = Point::new(16, 16);\n" +"\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(p1);\n" +" poly.add_point(p2);\n" +"\n" +" let points = poly.iter().cloned().collect::>();\n" +" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_shape_perimeters() {\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(Point::new(12, 13));\n" +" poly.add_point(Point::new(17, 11));\n" +" poly.add_point(Point::new(16, 16));\n" +" let shapes = vec![\n" +" Shape::from(poly),\n" +" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" +" ];\n" +" let perimeters = shapes\n" +" .iter()\n" +" .map(Shape::perimeter)\n" +" .map(round_two_digits)\n" +" .collect::>();\n" +" assert_eq!(perimeters, vec![15.48, 31.42]);\n" +" }\n" +"}\n" +"\n" +"#[allow(dead_code)]\n" +"fn main() {}\n" +"```" +msgstr "" + +#: src/exercises/day-3/points-polygons.md:117 +msgid "" +"Since the method signatures are missing from the problem statements, the key " +"part of the exercise is to specify those correctly. You don't have to modify " +"the tests." +msgstr "" + +#: src/exercises/day-3/points-polygons.md:120 +msgid "Other interesting parts of the exercise:" +msgstr "" + +#: src/exercises/day-3/points-polygons.md:122 +msgid "" +"Derive a `Copy` trait for some structs, as in tests the methods sometimes " +"don't borrow their arguments." +msgstr "" + +#: src/exercises/day-3/points-polygons.md:123 +msgid "" +"Discover that `Add` trait must be implemented for two objects to be addable " +"via \"+\". Note that we do not discuss generics until Day 3." +msgstr "" + #: src/error-handling.md:3 msgid "Error handling in Rust is done using explicit control flow:" msgstr "" @@ -14104,7 +14074,7 @@ msgstr "" msgid "" "If it were running in a VM, this can lead to cache coherency issues. The " "problem is that the VM is accessing memory directly with the cache disabled, " -"while the host has cachable aliases to the same memory. Even if the host " +"while the host has cacheable aliases to the same memory. Even if the host " "doesn't explicitly access the memory, speculative accesses can lead to cache " "fills, and then changes from one or the other will get lost when the cache " "is cleaned or the VM enables the cache. (Cache is keyed by physical address, " @@ -15206,7 +15176,7 @@ msgstr "" msgid "" "If it were running in a VM, this can lead to cache coherency issues. The " "problem is that the VM is accessing memory directly with the cache disabled, " -"while the host has cachable aliases to the same memory. Even if the host " +"while the host has cacheable aliases to the same memory. Even if the host " "doesn't explicitly access the memory, speculative accesses can lead to cache " "fills, and then changes from one or the other will get lost. Again this is " "alright in this particular case (running directly on the hardware with no " @@ -18879,7 +18849,7 @@ msgid "" "In this example, we have a race between a cat and a dog. " "`first_animal_to_finish_race` listens to both channels and will pick " "whichever arrives first. Since the dog takes 50ms, it wins against the cat " -"that take 500ms seconds." +"that take 500ms." msgstr "" #: src/async/control-flow/select.md:67 @@ -19356,7 +19326,7 @@ msgstr "" #: src/async/pitfalls/cancellation.md:82 msgid "" -"`LinesReader` can be made cancellation-safe by makeing `buf` part of the " +"`LinesReader` can be made cancellation-safe by making `buf` part of the " "struct:" msgstr "" @@ -19531,7 +19501,7 @@ msgstr "" msgid "" "For this, we use [a broadcast channel](https://docs.rs/tokio/latest/tokio/" "sync/broadcast/fn.channel.html) on the server, and [`tokio_websockets`]" -"(https://docs.rs/tokio-websockets/0.3.2/tokio_websockets/) for the " +"(https://docs.rs/tokio-websockets/0.4.0/tokio_websockets/) for the " "communication between the client and the server." msgstr "" @@ -19552,10 +19522,11 @@ msgid "" "edition = \"2021\"\n" "\n" "[dependencies]\n" -"futures-util = \"0.3.28\"\n" +"futures-util = { version = \"0.3.28\", features = [\"sink\"] }\n" "http = \"0.2.9\"\n" "tokio = { version = \"1.28.1\", features = [\"full\"] }\n" -"tokio-websockets = \"0.3.2\"\n" +"tokio-websockets = { version = \"0.4.0\", features = [\"client\", " +"\"fastrand\", \"server\", \"sha1_smol\"] }\n" "```" msgstr "" @@ -19566,15 +19537,15 @@ msgstr "" #: src/exercises/concurrency/chat-app.md:33 msgid "" "You are going to need the following functions from `tokio` and " -"[`tokio_websockets`](https://docs.rs/tokio-websockets/0.3.2/" +"[`tokio_websockets`](https://docs.rs/tokio-websockets/0.4.0/" "tokio_websockets/). Spend a few minutes to familiarize yourself with the " "API. " msgstr "" #: src/exercises/concurrency/chat-app.md:37 msgid "" -"[WebsocketStream::next()](https://docs.rs/tokio-websockets/0.3.2/" -"tokio_websockets/proto/struct.WebsocketStream.html#method.next): for " +"[StreamExt::next()](https://docs.rs/futures-util/0.3.28/futures_util/stream/" +"trait.StreamExt.html#method.next) implemented by `WebsocketStream`: for " "asynchronously reading messages from a Websocket Stream." msgstr "" @@ -19629,6 +19600,7 @@ msgstr "`src/bin/server.rs`:" msgid "" "```rust,compile_fail\n" "use futures_util::sink::SinkExt;\n" +"use futures_util::stream::StreamExt;\n" "use std::error::Error;\n" "use std::net::SocketAddr;\n" "use tokio::net::{TcpListener, TcpStream};\n" @@ -19667,14 +19639,15 @@ msgid "" "```" msgstr "" -#: src/exercises/concurrency/chat-app.md:102 -#: src/exercises/concurrency/solutions-afternoon.md:208 +#: src/exercises/concurrency/chat-app.md:103 +#: src/exercises/concurrency/solutions-afternoon.md:210 msgid "`src/bin/client.rs`:" msgstr "`src/bin/client.rs`:" -#: src/exercises/concurrency/chat-app.md:106 +#: src/exercises/concurrency/chat-app.md:107 msgid "" "```rust,compile_fail\n" +"use futures_util::stream::StreamExt;\n" "use futures_util::SinkExt;\n" "use http::Uri;\n" "use tokio::io::{AsyncBufReadExt, BufReader};\n" @@ -19682,10 +19655,10 @@ msgid "" "\n" "#[tokio::main]\n" "async fn main() -> Result<(), tokio_websockets::Error> {\n" -" let mut ws_stream = ClientBuilder::from_uri(Uri::" -"from_static(\"ws://127.0.0.1:2000\"))\n" -" .connect()\n" -" .await?;\n" +" let (mut ws_stream, _) =\n" +" ClientBuilder::from_uri(Uri::from_static(\"ws://127.0.0.1:2000\"))\n" +" .connect()\n" +" .await?;\n" "\n" " let stdin = tokio::io::stdin();\n" " let mut stdin = BufReader::new(stdin).lines();\n" @@ -19697,48 +19670,48 @@ msgid "" "```" msgstr "" -#: src/exercises/concurrency/chat-app.md:127 +#: src/exercises/concurrency/chat-app.md:130 msgid "Running the binaries" msgstr "Afvikling af binære filer" -#: src/exercises/concurrency/chat-app.md:128 +#: src/exercises/concurrency/chat-app.md:131 msgid "Run the server with:" msgstr "" -#: src/exercises/concurrency/chat-app.md:130 +#: src/exercises/concurrency/chat-app.md:133 msgid "" "```shell\n" "cargo run --bin server\n" "```" msgstr "" -#: src/exercises/concurrency/chat-app.md:134 +#: src/exercises/concurrency/chat-app.md:137 msgid "and the client with:" msgstr "" -#: src/exercises/concurrency/chat-app.md:136 +#: src/exercises/concurrency/chat-app.md:139 msgid "" "```shell\n" "cargo run --bin client\n" "```" msgstr "" -#: src/exercises/concurrency/chat-app.md:142 +#: src/exercises/concurrency/chat-app.md:145 msgid "Implement the `handle_connection` function in `src/bin/server.rs`." msgstr "" -#: src/exercises/concurrency/chat-app.md:143 +#: src/exercises/concurrency/chat-app.md:146 msgid "" "Hint: Use `tokio::select!` for concurrently performing two tasks in a " "continuous loop. One task receives messages from the client and broadcasts " "them. The other sends messages received by the server to the client." msgstr "" -#: src/exercises/concurrency/chat-app.md:146 +#: src/exercises/concurrency/chat-app.md:149 msgid "Complete the main function in `src/bin/client.rs`." msgstr "" -#: src/exercises/concurrency/chat-app.md:147 +#: src/exercises/concurrency/chat-app.md:150 msgid "" "Hint: As before, use `tokio::select!` in a continuous loop for concurrently " "performing two tasks: (1) reading user messages from standard input and " @@ -19746,7 +19719,7 @@ msgid "" "displaying them for the user." msgstr "" -#: src/exercises/concurrency/chat-app.md:151 +#: src/exercises/concurrency/chat-app.md:154 msgid "" "Optional: Once you are done, change the code to broadcast messages to all " "clients, but the sender of the message." @@ -20117,15 +20090,216 @@ msgstr "" msgid "Day 1 Afternoon Exercises" msgstr "" -#: src/exercises/day-1/solutions-afternoon.md:3 +#: src/exercises/day-1/solutions-afternoon.md:5 +msgid "([back to exercise](luhn.md))" +msgstr "([tilbage til øvelsen](luhn.md))" + +#: src/exercises/day-1/solutions-afternoon.md:7 +msgid "" +"```rust\n" +"// Copyright 2022 Google LLC\n" +"//\n" +"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +"// you may not use this file except in compliance with the License.\n" +"// You may obtain a copy of the License at\n" +"//\n" +"// http://www.apache.org/licenses/LICENSE-2.0\n" +"//\n" +"// Unless required by applicable law or agreed to in writing, software\n" +"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +"// See the License for the specific language governing permissions and\n" +"// limitations under the License.\n" +"\n" +"// ANCHOR: luhn\n" +"pub fn luhn(cc_number: &str) -> bool {\n" +" // ANCHOR_END: luhn\n" +" let mut digits_seen = 0;\n" +" let mut sum = 0;\n" +" for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ')." +"enumerate() {\n" +" match ch.to_digit(10) {\n" +" Some(d) => {\n" +" sum += if i % 2 == 1 {\n" +" let dd = d * 2;\n" +" dd / 10 + dd % 10\n" +" } else {\n" +" d\n" +" };\n" +" digits_seen += 1;\n" +" }\n" +" None => return false,\n" +" }\n" +" }\n" +"\n" +" if digits_seen < 2 {\n" +" return false;\n" +" }\n" +"\n" +" sum % 10 == 0\n" +"}\n" +"\n" +"fn main() {\n" +" let cc_number = \"1234 5678 1234 5670\";\n" +" println!(\n" +" \"Is {cc_number} a valid credit card number? {}\",\n" +" if luhn(cc_number) { \"yes\" } else { \"no\" }\n" +" );\n" +"}\n" +"\n" +"// ANCHOR: unit-tests\n" +"#[test]\n" +"fn test_non_digit_cc_number() {\n" +" assert!(!luhn(\"foo\"));\n" +" assert!(!luhn(\"foo 0 0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_empty_cc_number() {\n" +" assert!(!luhn(\"\"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_single_digit_cc_number() {\n" +" assert!(!luhn(\"0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_two_digit_cc_number() {\n" +" assert!(luhn(\" 0 0 \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_valid_cc_number() {\n" +" assert!(luhn(\"4263 9826 4026 9299\"));\n" +" assert!(luhn(\"4539 3195 0343 6467\"));\n" +" assert!(luhn(\"7992 7398 713\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_invalid_cc_number() {\n" +" assert!(!luhn(\"4223 9826 4026 9299\"));\n" +" assert!(!luhn(\"4539 3195 0343 6476\"));\n" +" assert!(!luhn(\"8273 1232 7352 0569\"));\n" +"}\n" +"// ANCHOR_END: unit-tests\n" +"```" +msgstr "" +"```rust\n" +"// Copyright 2022 Google LLC\n" +"//\n" +"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +"// you may not use this file except in compliance with the License.\n" +"// You may obtain a copy of the License at\n" +"//\n" +"// http://www.apache.org/licenses/LICENSE-2.0\n" +"//\n" +"// Unless required by applicable law or agreed to in writing, software\n" +"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +"// See the License for the specific language governing permissions and\n" +"// limitations under the License.\n" +"\n" +"// ANCHOR: luhn\n" +"pub fn luhn(cc_number: &str) -> bool {\n" +" // ANCHOR_END: luhn\n" +" let mut digits_seen = 0;\n" +" let mut sum = 0;\n" +" for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ').enumerate() {\n" +" match ch.to_digit(10) {\n" +" Some(d) => {\n" +" sum += if i % 2 == 1 {\n" +" let dd = d * 2;\n" +" dd / 10 + dd % 10\n" +" } else {\n" +" d\n" +" };\n" +" digits_seen += 1;\n" +" }\n" +" None => return false,\n" +" }\n" +" }\n" +"\n" +" if digits_seen < 2 {\n" +" return false;\n" +" }\n" +"\n" +" sum % 10 == 0\n" +"}\n" +"\n" +"fn main() {\n" +" let cc_number = \"1234 5678 1234 5670\";\n" +" println!(\n" +" \"Er {cc_number} et gyldigt kreditkortnummer? {}\",\n" +" if luhn(cc_number) { \"ja\" } else { \"nej\" }\n" +" );\n" +"}\n" +"\n" +"// ANCHOR: unit-tests\n" +"#[test]\n" +"fn test_non_digit_cc_number() {\n" +" assert!(!luhn(\"foo\"));\n" +" assert!(!luhn(\"foo 0 0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_empty_cc_number() {\n" +" assert!(!luhn(\"\"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +" assert!(!luhn(\" \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_single_digit_cc_number() {\n" +" assert!(!luhn(\"0\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_two_digit_cc_number() {\n" +" assert!(luhn(\" 0 0 \"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_valid_cc_number() {\n" +" assert!(luhn(\"4263 9826 4026 9299\"));\n" +" assert!(luhn(\"4539 3195 0343 6467\"));\n" +" assert!(luhn(\"7992 7398 713\"));\n" +"}\n" +"\n" +"#[test]\n" +"fn test_invalid_cc_number() {\n" +" assert!(!luhn(\"4223 9826 4026 9299\"));\n" +" assert!(!luhn(\"4539 3195 0343 6476\"));\n" +" assert!(!luhn(\"8273 1232 7352 0569\"));\n" +"}\n" +"// ANCHOR_END: unit-tests\n" +"```" + +#: src/exercises/day-1/solutions-afternoon.md:98 +msgid "Pattern matching" +msgstr "Mønstergenkendelse" + +#: src/exercises/day-1/solutions-afternoon.md:100 +msgid "TBD." +msgstr "" + +#: src/exercises/day-2/solutions-morning.md:1 +msgid "Day 2 Morning Exercises" +msgstr "Dag 2 formiddagsøvelser" + +#: src/exercises/day-2/solutions-morning.md:3 msgid "Designing a Library" msgstr "Design af et bibliotek" -#: src/exercises/day-1/solutions-afternoon.md:5 +#: src/exercises/day-2/solutions-morning.md:5 msgid "([back to exercise](book-library.md))" msgstr "([tilbage til øvelsen](book-library.md))" -#: src/exercises/day-1/solutions-afternoon.md:7 +#: src/exercises/day-2/solutions-morning.md:7 msgid "" "```rust\n" "// Copyright 2022 Google LLC\n" @@ -20206,7 +20380,7 @@ msgid "" "\n" " // ANCHOR: Library_print_books\n" " //fn print_books(self) {\n" -" // todo!(\"Iterate over `self.books` and each book's title and " +" // todo!(\"Iterate over `self.books` and print each book's title and " "year\")\n" " //}\n" " // ANCHOR_END: Library_print_books\n" @@ -20322,454 +20496,15 @@ msgid "" "```" msgstr "" -#: src/exercises/day-2/solutions-morning.md:1 -msgid "Day 2 Morning Exercises" -msgstr "Dag 2 formiddagsøvelser" - -#: src/exercises/day-2/solutions-morning.md:5 -msgid "([back to exercise](points-polygons.md))" -msgstr "([tilbage til øvelsen](points-polygons.md))" - -#: src/exercises/day-2/solutions-morning.md:7 -msgid "" -"```rust\n" -"// Copyright 2022 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"#[derive(Debug, Copy, Clone, PartialEq, Eq)]\n" -"// ANCHOR: Point\n" -"pub struct Point {\n" -" // ANCHOR_END: Point\n" -" x: i32,\n" -" y: i32,\n" -"}\n" -"\n" -"// ANCHOR: Point-impl\n" -"impl Point {\n" -" // ANCHOR_END: Point-impl\n" -" pub fn new(x: i32, y: i32) -> Point {\n" -" Point { x, y }\n" -" }\n" -"\n" -" pub fn magnitude(self) -> f64 {\n" -" f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()\n" -" }\n" -"\n" -" pub fn dist(self, other: Point) -> f64 {\n" -" (self - other).magnitude()\n" -" }\n" -"}\n" -"\n" -"impl std::ops::Add for Point {\n" -" type Output = Self;\n" -"\n" -" fn add(self, other: Self) -> Self::Output {\n" -" Self {\n" -" x: self.x + other.x,\n" -" y: self.y + other.y,\n" -" }\n" -" }\n" -"}\n" -"\n" -"impl std::ops::Sub for Point {\n" -" type Output = Self;\n" -"\n" -" fn sub(self, other: Self) -> Self::Output {\n" -" Self {\n" -" x: self.x - other.x,\n" -" y: self.y - other.y,\n" -" }\n" -" }\n" -"}\n" -"\n" -"// ANCHOR: Polygon\n" -"pub struct Polygon {\n" -" // ANCHOR_END: Polygon\n" -" points: Vec,\n" -"}\n" -"\n" -"// ANCHOR: Polygon-impl\n" -"impl Polygon {\n" -" // ANCHOR_END: Polygon-impl\n" -" pub fn new() -> Polygon {\n" -" Polygon { points: Vec::new() }\n" -" }\n" -"\n" -" pub fn add_point(&mut self, point: Point) {\n" -" self.points.push(point);\n" -" }\n" -"\n" -" pub fn left_most_point(&self) -> Option {\n" -" self.points.iter().min_by_key(|p| p.x).copied()\n" -" }\n" -"\n" -" pub fn iter(&self) -> impl Iterator {\n" -" self.points.iter()\n" -" }\n" -"\n" -" pub fn length(&self) -> f64 {\n" -" if self.points.is_empty() {\n" -" return 0.0;\n" -" }\n" -"\n" -" let mut result = 0.0;\n" -" let mut last_point = self.points[0];\n" -" for point in &self.points[1..] {\n" -" result += last_point.dist(*point);\n" -" last_point = *point;\n" -" }\n" -" result += last_point.dist(self.points[0]);\n" -" result\n" -" // Alternatively, Iterator::zip() lets us iterate over the points as " -"pairs\n" -" // but we need to pair each point with the next one, and the last " -"point\n" -" // with the first point. The zip() iterator is finished as soon as " -"one of \n" -" // the source iterators is finished, a neat trick is to combine " -"Iterator::cycle\n" -" // with Iterator::skip to create the second iterator for the zip and " -"using map \n" -" // and sum to calculate the total length.\n" -" }\n" -"}\n" -"\n" -"// ANCHOR: Circle\n" -"pub struct Circle {\n" -" // ANCHOR_END: Circle\n" -" center: Point,\n" -" radius: i32,\n" -"}\n" -"\n" -"// ANCHOR: Circle-impl\n" -"impl Circle {\n" -" // ANCHOR_END: Circle-impl\n" -" pub fn new(center: Point, radius: i32) -> Circle {\n" -" Circle { center, radius }\n" -" }\n" -"\n" -" pub fn circumference(&self) -> f64 {\n" -" 2.0 * std::f64::consts::PI * f64::from(self.radius)\n" -" }\n" -"\n" -" pub fn dist(&self, other: &Self) -> f64 {\n" -" self.center.dist(other.center)\n" -" }\n" -"}\n" -"\n" -"// ANCHOR: Shape\n" -"pub enum Shape {\n" -" Polygon(Polygon),\n" -" Circle(Circle),\n" -"}\n" -"// ANCHOR_END: Shape\n" -"\n" -"impl From for Shape {\n" -" fn from(poly: Polygon) -> Self {\n" -" Shape::Polygon(poly)\n" -" }\n" -"}\n" -"\n" -"impl From for Shape {\n" -" fn from(circle: Circle) -> Self {\n" -" Shape::Circle(circle)\n" -" }\n" -"}\n" -"\n" -"impl Shape {\n" -" pub fn perimeter(&self) -> f64 {\n" -" match self {\n" -" Shape::Polygon(poly) => poly.length(),\n" -" Shape::Circle(circle) => circle.circumference(),\n" -" }\n" -" }\n" -"}\n" -"\n" -"// ANCHOR: unit-tests\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::*;\n" -"\n" -" fn round_two_digits(x: f64) -> f64 {\n" -" (x * 100.0).round() / 100.0\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_magnitude() {\n" -" let p1 = Point::new(12, 13);\n" -" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_dist() {\n" -" let p1 = Point::new(10, 10);\n" -" let p2 = Point::new(14, 13);\n" -" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_point_add() {\n" -" let p1 = Point::new(16, 16);\n" -" let p2 = p1 + Point::new(-4, 3);\n" -" assert_eq!(p2, Point::new(12, 19));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_left_most_point() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -" assert_eq!(poly.left_most_point(), Some(p1));\n" -" }\n" -"\n" -" #[test]\n" -" fn test_polygon_iter() {\n" -" let p1 = Point::new(12, 13);\n" -" let p2 = Point::new(16, 16);\n" -"\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(p1);\n" -" poly.add_point(p2);\n" -"\n" -" let points = poly.iter().cloned().collect::>();\n" -" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" -" }\n" -"\n" -" #[test]\n" -" fn test_shape_perimeters() {\n" -" let mut poly = Polygon::new();\n" -" poly.add_point(Point::new(12, 13));\n" -" poly.add_point(Point::new(17, 11));\n" -" poly.add_point(Point::new(16, 16));\n" -" let shapes = vec![\n" -" Shape::from(poly),\n" -" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" -" ];\n" -" let perimeters = shapes\n" -" .iter()\n" -" .map(Shape::perimeter)\n" -" .map(round_two_digits)\n" -" .collect::>();\n" -" assert_eq!(perimeters, vec![15.48, 31.42]);\n" -" }\n" -"}\n" -"// ANCHOR_END: unit-tests\n" -"\n" -"fn main() {}\n" -"```" -msgstr "" - #: src/exercises/day-2/solutions-afternoon.md:1 msgid "Day 2 Afternoon Exercises" msgstr "" #: src/exercises/day-2/solutions-afternoon.md:5 -msgid "([back to exercise](luhn.md))" -msgstr "([tilbage til øvelsen](luhn.md))" - -#: src/exercises/day-2/solutions-afternoon.md:7 -msgid "" -"```rust\n" -"// Copyright 2022 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"// ANCHOR: luhn\n" -"pub fn luhn(cc_number: &str) -> bool {\n" -" // ANCHOR_END: luhn\n" -" let mut digits_seen = 0;\n" -" let mut sum = 0;\n" -" for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ')." -"enumerate() {\n" -" match ch.to_digit(10) {\n" -" Some(d) => {\n" -" sum += if i % 2 == 1 {\n" -" let dd = d * 2;\n" -" dd / 10 + dd % 10\n" -" } else {\n" -" d\n" -" };\n" -" digits_seen += 1;\n" -" }\n" -" None => return false,\n" -" }\n" -" }\n" -"\n" -" if digits_seen < 2 {\n" -" return false;\n" -" }\n" -"\n" -" sum % 10 == 0\n" -"}\n" -"\n" -"fn main() {\n" -" let cc_number = \"1234 5678 1234 5670\";\n" -" println!(\n" -" \"Is {cc_number} a valid credit card number? {}\",\n" -" if luhn(cc_number) { \"yes\" } else { \"no\" }\n" -" );\n" -"}\n" -"\n" -"// ANCHOR: unit-tests\n" -"#[test]\n" -"fn test_non_digit_cc_number() {\n" -" assert!(!luhn(\"foo\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty_cc_number() {\n" -" assert!(!luhn(\"\"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_digit_cc_number() {\n" -" assert!(!luhn(\"0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_two_digit_cc_number() {\n" -" assert!(luhn(\" 0 0 \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_valid_cc_number() {\n" -" assert!(luhn(\"4263 9826 4026 9299\"));\n" -" assert!(luhn(\"4539 3195 0343 6467\"));\n" -" assert!(luhn(\"7992 7398 713\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_invalid_cc_number() {\n" -" assert!(!luhn(\"4223 9826 4026 9299\"));\n" -" assert!(!luhn(\"4539 3195 0343 6476\"));\n" -" assert!(!luhn(\"8273 1232 7352 0569\"));\n" -"}\n" -"// ANCHOR_END: unit-tests\n" -"```" -msgstr "" -"```rust\n" -"// Copyright 2022 Google LLC\n" -"//\n" -"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" -"// you may not use this file except in compliance with the License.\n" -"// You may obtain a copy of the License at\n" -"//\n" -"// http://www.apache.org/licenses/LICENSE-2.0\n" -"//\n" -"// Unless required by applicable law or agreed to in writing, software\n" -"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" -"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" -"// See the License for the specific language governing permissions and\n" -"// limitations under the License.\n" -"\n" -"// ANCHOR: luhn\n" -"pub fn luhn(cc_number: &str) -> bool {\n" -" // ANCHOR_END: luhn\n" -" let mut digits_seen = 0;\n" -" let mut sum = 0;\n" -" for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ')." -"enumerate() {\n" -" match ch.to_digit(10) {\n" -" Some(d) => {\n" -" sum += if i % 2 == 1 {\n" -" let dd = d * 2;\n" -" dd / 10 + dd % 10\n" -" } else {\n" -" d\n" -" };\n" -" digits_seen += 1;\n" -" }\n" -" None => return false,\n" -" }\n" -" }\n" -"\n" -" if digits_seen < 2 {\n" -" return false;\n" -" }\n" -"\n" -" sum % 10 == 0\n" -"}\n" -"\n" -"fn main() {\n" -" let cc_number = \"1234 5678 1234 5670\";\n" -" println!(\n" -" \"Is {cc_number} a valid credit card number? {}\",\n" -" if luhn(cc_number) { \"yes\" } else { \"no\" }\n" -" );\n" -"}\n" -"\n" -"// ANCHOR: unit-tests\n" -"#[test]\n" -"fn test_non_digit_cc_number() {\n" -" assert!(!luhn(\"foo\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_empty_cc_number() {\n" -" assert!(!luhn(\"\"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -" assert!(!luhn(\" \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_single_digit_cc_number() {\n" -" assert!(!luhn(\"0\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_two_digit_cc_number() {\n" -" assert!(luhn(\" 0 0 \"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_valid_cc_number() {\n" -" assert!(luhn(\"4263 9826 4026 9299\"));\n" -" assert!(luhn(\"4539 3195 0343 6467\"));\n" -" assert!(luhn(\"7992 7398 713\"));\n" -"}\n" -"\n" -"#[test]\n" -"fn test_invalid_cc_number() {\n" -" assert!(!luhn(\"4223 9826 4026 9299\"));\n" -" assert!(!luhn(\"4539 3195 0343 6476\"));\n" -" assert!(!luhn(\"8273 1232 7352 0569\"));\n" -"}\n" -"// ANCHOR_END: unit-tests\n" -"```" - -#: src/exercises/day-2/solutions-afternoon.md:99 msgid "([back to exercise](strings-iterators.md))" msgstr "([tilbage til øvelsen](strings-iterators.md))" -#: src/exercises/day-2/solutions-afternoon.md:101 +#: src/exercises/day-2/solutions-afternoon.md:7 msgid "" "```rust\n" "// Copyright 2022 Google LLC\n" @@ -21123,6 +20858,253 @@ msgid "" "```" msgstr "" +#: src/exercises/day-3/solutions-morning.md:177 +msgid "([back to exercise](points-polygons.md))" +msgstr "([tilbage til øvelsen](points-polygons.md))" + +#: src/exercises/day-3/solutions-morning.md:179 +msgid "" +"```rust\n" +"// Copyright 2022 Google LLC\n" +"//\n" +"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +"// you may not use this file except in compliance with the License.\n" +"// You may obtain a copy of the License at\n" +"//\n" +"// http://www.apache.org/licenses/LICENSE-2.0\n" +"//\n" +"// Unless required by applicable law or agreed to in writing, software\n" +"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +"// See the License for the specific language governing permissions and\n" +"// limitations under the License.\n" +"\n" +"#[derive(Debug, Copy, Clone, PartialEq, Eq)]\n" +"// ANCHOR: Point\n" +"pub struct Point {\n" +" // ANCHOR_END: Point\n" +" x: i32,\n" +" y: i32,\n" +"}\n" +"\n" +"// ANCHOR: Point-impl\n" +"impl Point {\n" +" // ANCHOR_END: Point-impl\n" +" pub fn new(x: i32, y: i32) -> Point {\n" +" Point { x, y }\n" +" }\n" +"\n" +" pub fn magnitude(self) -> f64 {\n" +" f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()\n" +" }\n" +"\n" +" pub fn dist(self, other: Point) -> f64 {\n" +" (self - other).magnitude()\n" +" }\n" +"}\n" +"\n" +"impl std::ops::Add for Point {\n" +" type Output = Self;\n" +"\n" +" fn add(self, other: Self) -> Self::Output {\n" +" Self {\n" +" x: self.x + other.x,\n" +" y: self.y + other.y,\n" +" }\n" +" }\n" +"}\n" +"\n" +"impl std::ops::Sub for Point {\n" +" type Output = Self;\n" +"\n" +" fn sub(self, other: Self) -> Self::Output {\n" +" Self {\n" +" x: self.x - other.x,\n" +" y: self.y - other.y,\n" +" }\n" +" }\n" +"}\n" +"\n" +"// ANCHOR: Polygon\n" +"pub struct Polygon {\n" +" // ANCHOR_END: Polygon\n" +" points: Vec,\n" +"}\n" +"\n" +"// ANCHOR: Polygon-impl\n" +"impl Polygon {\n" +" // ANCHOR_END: Polygon-impl\n" +" pub fn new() -> Polygon {\n" +" Polygon { points: Vec::new() }\n" +" }\n" +"\n" +" pub fn add_point(&mut self, point: Point) {\n" +" self.points.push(point);\n" +" }\n" +"\n" +" pub fn left_most_point(&self) -> Option {\n" +" self.points.iter().min_by_key(|p| p.x).copied()\n" +" }\n" +"\n" +" pub fn iter(&self) -> impl Iterator {\n" +" self.points.iter()\n" +" }\n" +"\n" +" pub fn length(&self) -> f64 {\n" +" if self.points.is_empty() {\n" +" return 0.0;\n" +" }\n" +"\n" +" let mut result = 0.0;\n" +" let mut last_point = self.points[0];\n" +" for point in &self.points[1..] {\n" +" result += last_point.dist(*point);\n" +" last_point = *point;\n" +" }\n" +" result += last_point.dist(self.points[0]);\n" +" result\n" +" // Alternatively, Iterator::zip() lets us iterate over the points as " +"pairs\n" +" // but we need to pair each point with the next one, and the last " +"point\n" +" // with the first point. The zip() iterator is finished as soon as " +"one of \n" +" // the source iterators is finished, a neat trick is to combine " +"Iterator::cycle\n" +" // with Iterator::skip to create the second iterator for the zip and " +"using map \n" +" // and sum to calculate the total length.\n" +" }\n" +"}\n" +"\n" +"// ANCHOR: Circle\n" +"pub struct Circle {\n" +" // ANCHOR_END: Circle\n" +" center: Point,\n" +" radius: i32,\n" +"}\n" +"\n" +"// ANCHOR: Circle-impl\n" +"impl Circle {\n" +" // ANCHOR_END: Circle-impl\n" +" pub fn new(center: Point, radius: i32) -> Circle {\n" +" Circle { center, radius }\n" +" }\n" +"\n" +" pub fn circumference(&self) -> f64 {\n" +" 2.0 * std::f64::consts::PI * f64::from(self.radius)\n" +" }\n" +"\n" +" pub fn dist(&self, other: &Self) -> f64 {\n" +" self.center.dist(other.center)\n" +" }\n" +"}\n" +"\n" +"// ANCHOR: Shape\n" +"pub enum Shape {\n" +" Polygon(Polygon),\n" +" Circle(Circle),\n" +"}\n" +"// ANCHOR_END: Shape\n" +"\n" +"impl From for Shape {\n" +" fn from(poly: Polygon) -> Self {\n" +" Shape::Polygon(poly)\n" +" }\n" +"}\n" +"\n" +"impl From for Shape {\n" +" fn from(circle: Circle) -> Self {\n" +" Shape::Circle(circle)\n" +" }\n" +"}\n" +"\n" +"impl Shape {\n" +" pub fn perimeter(&self) -> f64 {\n" +" match self {\n" +" Shape::Polygon(poly) => poly.length(),\n" +" Shape::Circle(circle) => circle.circumference(),\n" +" }\n" +" }\n" +"}\n" +"\n" +"// ANCHOR: unit-tests\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::*;\n" +"\n" +" fn round_two_digits(x: f64) -> f64 {\n" +" (x * 100.0).round() / 100.0\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_magnitude() {\n" +" let p1 = Point::new(12, 13);\n" +" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_dist() {\n" +" let p1 = Point::new(10, 10);\n" +" let p2 = Point::new(14, 13);\n" +" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_point_add() {\n" +" let p1 = Point::new(16, 16);\n" +" let p2 = p1 + Point::new(-4, 3);\n" +" assert_eq!(p2, Point::new(12, 19));\n" +" }\n" +"\n" +" #[test]\n" +" fn test_polygon_left_most_point() {\n" +" let p1 = Point::new(12, 13);\n" +" let p2 = Point::new(16, 16);\n" +"\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(p1);\n" +" poly.add_point(p2);\n" +" assert_eq!(poly.left_most_point(), Some(p1));\n" +" }\n" +"\n" +" #[test]\n" +" fn test_polygon_iter() {\n" +" let p1 = Point::new(12, 13);\n" +" let p2 = Point::new(16, 16);\n" +"\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(p1);\n" +" poly.add_point(p2);\n" +"\n" +" let points = poly.iter().cloned().collect::>();\n" +" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n" +" }\n" +"\n" +" #[test]\n" +" fn test_shape_perimeters() {\n" +" let mut poly = Polygon::new();\n" +" poly.add_point(Point::new(12, 13));\n" +" poly.add_point(Point::new(17, 11));\n" +" poly.add_point(Point::new(16, 16));\n" +" let shapes = vec![\n" +" Shape::from(poly),\n" +" Shape::from(Circle::new(Point::new(10, 20), 5)),\n" +" ];\n" +" let perimeters = shapes\n" +" .iter()\n" +" .map(Shape::perimeter)\n" +" .map(round_two_digits)\n" +" .collect::>();\n" +" assert_eq!(perimeters, vec![15.48, 31.42]);\n" +" }\n" +"}\n" +"// ANCHOR_END: unit-tests\n" +"\n" +"fn main() {}\n" +"```" +msgstr "" + #: src/exercises/day-3/solutions-afternoon.md:1 msgid "Day 3 Afternoon Exercises" msgstr "" @@ -22252,6 +22234,7 @@ msgid "" "\n" "// ANCHOR: setup\n" "use futures_util::sink::SinkExt;\n" +"use futures_util::stream::StreamExt;\n" "use std::error::Error;\n" "use std::net::SocketAddr;\n" "use tokio::net::{TcpListener, TcpStream};\n" @@ -22281,9 +22264,10 @@ msgid "" " incoming = ws_stream.next() => {\n" " match incoming {\n" " Some(Ok(msg)) => {\n" -" let msg = msg.as_text()?;\n" -" println!(\"From client {addr:?} {msg:?}\");\n" -" bcast_tx.send(msg.into())?;\n" +" if let Some(text) = msg.as_text() {\n" +" println!(\"From client {addr:?} {text:?}\");\n" +" bcast_tx.send(text.into())?;\n" +" }\n" " }\n" " Some(Err(err)) => return Err(err.into()),\n" " None => return Ok(()),\n" @@ -22320,7 +22304,7 @@ msgid "" "```" msgstr "" -#: src/exercises/concurrency/solutions-afternoon.md:210 +#: src/exercises/concurrency/solutions-afternoon.md:212 msgid "" "```rust,compile_fail\n" "// Copyright 2023 Google LLC\n" @@ -22338,6 +22322,7 @@ msgid "" "// limitations under the License.\n" "\n" "// ANCHOR: setup\n" +"use futures_util::stream::StreamExt;\n" "use futures_util::SinkExt;\n" "use http::Uri;\n" "use tokio::io::{AsyncBufReadExt, BufReader};\n" @@ -22345,10 +22330,10 @@ msgid "" "\n" "#[tokio::main]\n" "async fn main() -> Result<(), tokio_websockets::Error> {\n" -" let mut ws_stream = ClientBuilder::from_uri(Uri::" -"from_static(\"ws://127.0.0.1:2000\"))\n" -" .connect()\n" -" .await?;\n" +" let (mut ws_stream, _) =\n" +" ClientBuilder::from_uri(Uri::from_static(\"ws://127.0.0.1:2000\"))\n" +" .connect()\n" +" .await?;\n" "\n" " let stdin = tokio::io::stdin();\n" " let mut stdin = BufReader::new(stdin).lines();\n" @@ -22359,8 +22344,11 @@ msgid "" " tokio::select! {\n" " incoming = ws_stream.next() => {\n" " match incoming {\n" -" Some(Ok(msg)) => println!(\"From server: {}\", msg." -"as_text()?),\n" +" Some(Ok(msg)) => {\n" +" if let Some(text) = msg.as_text() {\n" +" println!(\"From server: {}\", text);\n" +" }\n" +" },\n" " Some(Err(err)) => return Err(err.into()),\n" " None => return Ok(()),\n" " }\n" @@ -22379,3 +22367,9 @@ msgid "" "}\n" "```" msgstr "" + +#~ msgid "Comparison" +#~ msgstr "Sammenligning" + +#~ msgid "Extra Work in Modern C++" +#~ msgstr "Defensiv kopiering i moderne C++"