From c9e89f1411bba041dba863a87a397f8081f9806f Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Sat, 17 May 2025 14:07:03 +0900 Subject: [PATCH 01/12] Added ja.po --- po/ja.po | 7212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 7212 insertions(+) create mode 100644 po/ja.po diff --git a/po/ja.po b/po/ja.po new file mode 100644 index 00000000..46474640 --- /dev/null +++ b/po/ja.po @@ -0,0 +1,7212 @@ +msgid "" +msgstr "" +"Project-Id-Version: Rust Design Patterns\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2025-05-17 14:04+0900\n" +"Last-Translator: Koji Murata \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 3.6\n" + +#: src\SUMMARY.md:3 +msgid "Introduction" +msgstr "序文" + +#: src\SUMMARY.md:4 +msgid "Translations" +msgstr "翻訳" + +#: src\SUMMARY.md:5 +msgid "Idioms" +msgstr "慣習" + +#: src\SUMMARY.md:6 +msgid "Use borrowed types for arguments" +msgstr "引数には借用型を使う" + +#: src\SUMMARY.md:7 +msgid "Concatenating Strings with format!" +msgstr "format! による文字列連結" + +#: src\SUMMARY.md:8 +msgid "Constructor" +msgstr "コンストラクタ" + +#: src\SUMMARY.md:9 +msgid "The Default Trait" +msgstr "Defaultトレイトの活用" + +#: src\SUMMARY.md:10 +msgid "Collections Are Smart Pointers" +msgstr "コレクションはスマートポインタである" + +#: src\SUMMARY.md:11 +msgid "Finalisation in Destructors" +msgstr "デストラクタでの後処理" + +#: src\SUMMARY.md:12 +msgid "mem::{take(_), replace(_)}" +msgstr "mem::{take(_), replace(_)}" + +#: src\SUMMARY.md:13 +msgid "On-Stack Dynamic Dispatch" +msgstr "スタック上での動的ディスパッチ" + +#: src\SUMMARY.md:14 src\SUMMARY.md:40 +msgid "Foreign function interface (FFI)" +msgstr "外部関数インターフェース(FFI)" + +#: src\SUMMARY.md:15 +msgid "Idiomatic Errors" +msgstr "FFIに適したエラー処理" + +#: src\SUMMARY.md:16 +msgid "Accepting Strings" +msgstr "文字列の受け取り方" + +#: src\SUMMARY.md:17 +msgid "Passing Strings" +msgstr "文字列の渡し方" + +#: src\SUMMARY.md:18 +msgid "Iterating over an Option" +msgstr "Optionをイテレータとして使う" + +#: src\SUMMARY.md:19 +msgid "Pass Variables to Closure" +msgstr "クロージャの変数キャプチャ" + +#: src\SUMMARY.md:20 +msgid "Privacy For Extensibility" +msgstr "拡張性のためのプライバシー制御" + +#: src\SUMMARY.md:21 +msgid "Easy doc initialization" +msgstr "ドキュメント用の初期化の簡素化" + +#: src\SUMMARY.md:22 +msgid "Temporary mutability" +msgstr "一時的な可変性" + +#: src\SUMMARY.md:23 +msgid "Return consumed arg on error" +msgstr "消費した引数をエラー時に返す" + +#: src\SUMMARY.md:25 +msgid "Design Patterns" +msgstr "" + +#: src\SUMMARY.md:26 +msgid "Behavioural" +msgstr "" + +#: src\SUMMARY.md:27 +msgid "Command" +msgstr "" + +#: src\SUMMARY.md:28 +msgid "Interpreter" +msgstr "" + +#: src\SUMMARY.md:29 +msgid "Newtype" +msgstr "" + +#: src\SUMMARY.md:30 +msgid "RAII Guards" +msgstr "" + +#: src\SUMMARY.md:31 +msgid "Strategy" +msgstr "" + +#: src\SUMMARY.md:32 +msgid "Visitor" +msgstr "" + +#: src\SUMMARY.md:33 +msgid "Creational" +msgstr "" + +#: src\SUMMARY.md:34 +msgid "Builder" +msgstr "" + +#: src\SUMMARY.md:35 +msgid "Fold" +msgstr "" + +#: src\SUMMARY.md:36 +msgid "Structural" +msgstr "" + +#: src\SUMMARY.md:37 +msgid "Compose Structs" +msgstr "" + +#: src\SUMMARY.md:38 +msgid "Prefer Small Crates" +msgstr "" + +#: src\SUMMARY.md:39 +msgid "Contain unsafety in small modules" +msgstr "" + +#: src\SUMMARY.md:41 +msgid "Object-Based APIs" +msgstr "" + +#: src\SUMMARY.md:42 +msgid "Type Consolidation into Wrappers" +msgstr "" + +#: src\SUMMARY.md:44 +msgid "Anti-patterns" +msgstr "" + +#: src\SUMMARY.md:45 +msgid "Clone to satisfy the borrow checker" +msgstr "" + +#: src\SUMMARY.md:46 +msgid "#[deny(warnings)]" +msgstr "" + +#: src\SUMMARY.md:47 +msgid "Deref Polymorphism" +msgstr "" + +#: src\SUMMARY.md:49 +msgid "Functional Programming" +msgstr "" + +#: src\SUMMARY.md:50 +msgid "Programming paradigms" +msgstr "" + +#: src\SUMMARY.md:51 +msgid "Generics as Type Classes" +msgstr "" + +#: src\SUMMARY.md:52 +msgid "Lenses and Prisms" +msgstr "" + +#: src\SUMMARY.md:54 +msgid "Additional Resources" +msgstr "" + +#: src\SUMMARY.md:55 +msgid "Design principles" +msgstr "" + +#: src\intro.md:1 +msgid "# Introduction" +msgstr "" + +#: src\intro.md:3 +msgid "## Participation" +msgstr "参加する" + +#: src\intro.md:5 +msgid "" +"If you are interested in contributing to this book, check out the\n" +"[contribution guidelines](https://github.com/rust-unofficial/patterns/blob/" +"master/CONTRIBUTING.md)." +msgstr "" +"本書の執筆に貢献していただける方は、[コントリビューションガイドライン]" +"(https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md)をご" +"覧ください。" + +#: src\intro.md:8 +msgid "## Design patterns" +msgstr "" + +#: src\intro.md:10 +msgid "" +"In software development, we often come across problems that share\n" +"similarities regardless of the environment they appear in. Although the\n" +"implementation details are crucial to solve the task at hand, we may\n" +"abstract from these particularities to find the common practices that\n" +"are generically applicable." +msgstr "" + +#: src\intro.md:16 +msgid "" +"Design patterns are a collection of reusable and tested solutions to\n" +"recurring problems in engineering. They make our software more modular,\n" +"maintainable, and extensible. Moreover, these patterns provide a common\n" +"language for developers, making them an excellent tool for effective\n" +"communication when problem-solving in teams." +msgstr "" + +#: src\intro.md:22 src\patterns/index.md:14 +msgid "## Design patterns in Rust" +msgstr "" + +#: src\intro.md:24 +msgid "" +"Rust is not object-oriented, and the combination of all its " +"characteristics,\n" +"such as functional elements, a strong type system, and the borrow checker,\n" +"makes it unique.\n" +"Because of this, Rust design patterns vary with respect to other\n" +"traditional object-oriented programming languages.\n" +"That's why we decided to write this book. We hope you enjoy reading it!\n" +"The book is divided in three main chapters:" +msgstr "" + +#: src\intro.md:32 +msgid "" +"- [Idioms](./idioms/index.md): guidelines to follow when coding.\n" +" They are the social norms of the community.\n" +" You should break them only if you have a good reason for it.\n" +"- [Design patterns](./patterns/index.md): methods to solve common problems\n" +" when coding.\n" +"- [Anti-patterns](./anti_patterns/index.md): methods to solve common " +"problems\n" +" when coding.\n" +" However, while design patterns give us benefits,\n" +" anti-patterns create more problems." +msgstr "" + +#: src\translations.md:1 +msgid "# Translations" +msgstr "" + +#: src\translations.md:3 +msgid "" +"We are utilizing [mdbook-i18n-helper](https://github.com/google/mdbook-i18n-" +"helpers).\n" +"Please read up on how to _add_ and _update_ translations in [their " +"repository](https://github.com/google/mdbook-i18n-helpers#creating-and-" +"updating-translations)" +msgstr "" + +#: src\translations.md:6 +msgid "## External translations" +msgstr "" + +#: src\translations.md:8 +msgid "- [简体中文](https://fomalhauthmj.github.io/patterns/)" +msgstr "" + +#: src\translations.md:10 +msgid "" +"If you want to add a translation, please open an issue in the\n" +"[main repository](https://github.com/rust-unofficial/patterns)." +msgstr "" + +#: src\idioms/index.md:1 +msgid "# Idioms" +msgstr "" + +#: src\idioms/index.md:3 +msgid "" +"[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used\n" +"styles, guidelines and patterns largely agreed upon by a community.\n" +"Writing idiomatic code allows other developers to understand better what is\n" +"happening." +msgstr "" + +#: src\idioms/index.md:8 +msgid "" +"After all, the computer only cares about the machine code that is generated\n" +"by the compiler.\n" +"Instead, the source code is mainly beneficial to the developer.\n" +"So, since we have this abstraction layer, why not make it more readable?" +msgstr "" + +#: src\idioms/index.md:13 +msgid "" +"Remember the [KISS principle](https://en.wikipedia.org/wiki/" +"KISS_principle):\n" +"\"Keep It Simple, Stupid\". It claims that \"most systems work best if they " +"are\n" +"kept simple rather than made complicated; therefore, simplicity should be a " +"key\n" +"goal in design, and unnecessary complexity should be avoided\"." +msgstr "" + +#: src\idioms/index.md:18 +msgid "> Code is there for humans, not computers, to understand." +msgstr "" + +#: src\idioms/coercion-arguments.md:1 +msgid "# Use borrowed types for arguments" +msgstr "" + +#: src\idioms/coercion-arguments.md:3 src\idioms/concat-format.md:3 +#: src\idioms/default.md:3 src\idioms/deref.md:3 src\idioms/dtor-finally.md:3 +#: src\idioms/mem-replace.md:3 src\idioms/on-stack-dyn-dispatch.md:3 +#: src\idioms/ffi/errors.md:3 src\idioms/ffi/accepting-strings.md:3 +#: src\idioms/ffi/passing-strings.md:3 src\idioms/option-iter.md:3 +#: src\idioms/pass-var-to-closure.md:3 src\idioms/priv-extend.md:3 +#: src\idioms/temporary-mutability.md:3 +#: src\idioms/return-consumed-arg-on-error.md:3 +#: src\patterns/behavioural/command.md:3 +#: src\patterns/behavioural/interpreter.md:3 +#: src\patterns/behavioural/newtype.md:13 src\patterns/behavioural/RAII.md:3 +#: src\patterns/behavioural/strategy.md:3 src\patterns/behavioural/visitor.md:3 +#: src\patterns/creational/builder.md:3 src\patterns/creational/fold.md:3 +#: src\patterns/structural/compose-structs.md:5 +#: src\patterns/structural/small-crates.md:3 +#: src\patterns/structural/unsafe-mods.md:3 src\patterns/ffi/export.md:3 +#: src\patterns/ffi/wrappers.md:3 src\anti_patterns/borrow_clone.md:3 +#: src\anti_patterns/deny-warnings.md:3 src\anti_patterns/deref.md:3 +#: src\functional/generics-type-classes.md:3 +msgid "## Description" +msgstr "" + +#: src\idioms/coercion-arguments.md:5 +msgid "" +"Using a target of a deref coercion can increase the flexibility of your " +"code\n" +"when you are deciding which argument type to use for a function argument.\n" +"In this way, the function will accept more input types." +msgstr "" + +#: src\idioms/coercion-arguments.md:9 +msgid "" +"This is not limited to slice-able or fat pointer types.\n" +"In fact, you should always prefer using the **borrowed type** over\n" +"**borrowing the owned type**.\n" +"Such as `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`." +msgstr "" + +#: src\idioms/coercion-arguments.md:14 +msgid "" +"Using borrowed types you can avoid layers of indirection for those " +"instances\n" +"where the owned type already provides a layer of indirection. For instance, " +"a\n" +"`String` has a layer of indirection, so a `&String` will have two layers of\n" +"indirection. We can avoid this by using `&str` instead, and letting " +"`&String`\n" +"coerce to a `&str` whenever the function is invoked." +msgstr "" + +#: src\idioms/coercion-arguments.md:20 src\idioms/concat-format.md:10 +#: src\idioms/default.md:20 src\idioms/deref.md:9 src\idioms/dtor-finally.md:9 +#: src\idioms/mem-replace.md:11 src\idioms/on-stack-dyn-dispatch.md:10 +#: src\idioms/pass-var-to-closure.md:12 src\idioms/priv-extend.md:18 +#: src\idioms/temporary-mutability.md:12 +#: src\idioms/return-consumed-arg-on-error.md:8 +#: src\patterns/behavioural/command.md:18 +#: src\patterns/behavioural/newtype.md:18 src\patterns/behavioural/RAII.md:11 +#: src\patterns/behavioural/strategy.md:28 +#: src\patterns/behavioural/visitor.md:13 src\patterns/creational/builder.md:7 +#: src\patterns/creational/fold.md:12 +#: src\patterns/structural/compose-structs.md:17 +#: src\anti_patterns/borrow_clone.md:11 src\anti_patterns/deny-warnings.md:8 +#: src\anti_patterns/deref.md:8 src\functional/generics-type-classes.md:38 +msgid "## Example" +msgstr "" + +#: src\idioms/coercion-arguments.md:22 +msgid "" +"For this example, we will illustrate some differences for using `&String` as " +"a\n" +"function argument versus using a `&str`, but the ideas apply as well to " +"using\n" +"`&Vec` versus using a `&[T]` or using a `&Box` versus a `&T`." +msgstr "" + +#: src\idioms/coercion-arguments.md:26 +msgid "" +"Consider an example where we wish to determine if a word contains three\n" +"consecutive vowels. We don't need to own the string to determine this, so " +"we\n" +"will take a reference." +msgstr "" + +#: src\idioms/coercion-arguments.md:30 +msgid "The code might look something like this:" +msgstr "" + +#: src\idioms/coercion-arguments.md:32 +msgid "" +"```rust\n" +"fn three_vowels(word: &String) -> bool {\n" +" let mut vowel_count = 0;\n" +" for c in word.chars() {\n" +" match c {\n" +" 'a' | 'e' | 'i' | 'o' | 'u' => {\n" +" vowel_count += 1;\n" +" if vowel_count >= 3 {\n" +" return true\n" +" }\n" +" }\n" +" _ => vowel_count = 0\n" +" }\n" +" }\n" +" false\n" +"}\n" +"\n" +"fn main() {\n" +" let ferris = \"Ferris\".to_string();\n" +" let curious = \"Curious\".to_string();\n" +" println!(\"{}: {}\", ferris, three_vowels(&ferris));\n" +" println!(\"{}: {}\", curious, three_vowels(&curious));\n" +"\n" +" // This works fine, but the following two lines would fail:\n" +" // println!(\"Ferris: {}\", three_vowels(\"Ferris\"));\n" +" // println!(\"Curious: {}\", three_vowels(\"Curious\"));\n" +"\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:62 +msgid "" +"This works fine because we are passing a `&String` type as a parameter.\n" +"If we remove the comments on the last two lines, the example will fail. " +"This\n" +"is because a `&str` type will not coerce to a `&String` type. We can fix " +"this\n" +"by simply modifying the type for our argument." +msgstr "" + +#: src\idioms/coercion-arguments.md:67 +msgid "For instance, if we change our function declaration to:" +msgstr "" + +#: src\idioms/coercion-arguments.md:69 +msgid "" +"```rust, ignore\n" +"fn three_vowels(word: &str) -> bool {\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:73 +msgid "then both versions will compile and print the same output." +msgstr "" + +#: src\idioms/coercion-arguments.md:75 +msgid "" +"```bash\n" +"Ferris: false\n" +"Curious: true\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:80 +msgid "" +"But wait, that's not all! There is more to this story.\n" +"It's likely that you may say to yourself: that doesn't matter, I will never " +"be\n" +"using a `&'static str` as an input anyways (as we did when we used " +"`\"Ferris\"`).\n" +"Even ignoring this special example, you may still find that using `&str` " +"will\n" +"give you more flexibility than using a `&String`." +msgstr "" + +#: src\idioms/coercion-arguments.md:86 +msgid "" +"Let's now take an example where someone gives us a sentence, and we want to\n" +"determine if any of the words in the sentence contain three consecutive " +"vowels.\n" +"We probably should make use of the function we have already defined and " +"simply\n" +"feed in each word from the sentence." +msgstr "" + +#: src\idioms/coercion-arguments.md:91 +msgid "An example of this could look like this:" +msgstr "" + +#: src\idioms/coercion-arguments.md:93 +msgid "" +"```rust\n" +"fn three_vowels(word: &str) -> bool {\n" +" let mut vowel_count = 0;\n" +" for c in word.chars() {\n" +" match c {\n" +" 'a' | 'e' | 'i' | 'o' | 'u' => {\n" +" vowel_count += 1;\n" +" if vowel_count >= 3 {\n" +" return true\n" +" }\n" +" }\n" +" _ => vowel_count = 0\n" +" }\n" +" }\n" +" false\n" +"}\n" +"\n" +"fn main() {\n" +" let sentence_string =\n" +" \"Once upon a time, there was a friendly curious crab named " +"Ferris\".to_string();\n" +" for word in sentence_string.split(' ') {\n" +" if three_vowels(word) {\n" +" println!(\"{} has three consecutive vowels!\", word);\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:121 +msgid "" +"Running this example using our function declared with an argument type " +"`&str`\n" +"will yield" +msgstr "" + +#: src\idioms/coercion-arguments.md:124 +msgid "" +"```bash\n" +"curious has three consecutive vowels!\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:128 +msgid "" +"However, this example will not run when our function is declared with an\n" +"argument type `&String`. This is because string slices are a `&str` and not " +"a\n" +"`&String` which would require an allocation to be converted to `&String` " +"which\n" +"is not implicit, whereas converting from `String` to `&str` is cheap and " +"implicit." +msgstr "" + +#: src\idioms/coercion-arguments.md:133 src\idioms/default.md:58 +#: src\idioms/deref.md:76 src\idioms/dtor-finally.md:88 +#: src\idioms/mem-replace.md:108 src\idioms/on-stack-dyn-dispatch.md:83 +#: src\idioms/option-iter.md:46 src\idioms/priv-extend.md:120 +#: src\patterns/behavioural/command.md:218 +#: src\patterns/behavioural/interpreter.md:142 +#: src\patterns/behavioural/newtype.md:104 src\patterns/behavioural/RAII.md:111 +#: src\patterns/behavioural/strategy.md:174 +#: src\patterns/behavioural/visitor.md:106 +#: src\patterns/creational/builder.md:108 src\patterns/creational/fold.md:109 +#: src\patterns/structural/small-crates.md:45 +#: src\patterns/structural/unsafe-mods.md:32 +#: src\anti_patterns/borrow_clone.md:68 src\anti_patterns/deny-warnings.md:96 +#: src\anti_patterns/deref.md:123 src\functional/generics-type-classes.md:237 +msgid "## See also" +msgstr "" + +#: src\idioms/coercion-arguments.md:135 +msgid "" +"- [Rust Language Reference on Type Coercions](https://doc.rust-lang.org/" +"reference/type-coercions.html)\n" +"- For more discussion on how to handle `String` and `&str` see\n" +" [this blog series (2015)](https://web.archive.org/web/20201112023149/" +"https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html)\n" +" by Herman J. Radtke III" +msgstr "" + +#: src\idioms/concat-format.md:1 +msgid "# Concatenating strings with `format!`" +msgstr "" + +#: src\idioms/concat-format.md:5 +msgid "" +"It is possible to build up strings using the `push` and `push_str` methods " +"on a\n" +"mutable `String`, or using its `+` operator. However, it is often more\n" +"convenient to use `format!`, especially where there is a mix of literal and\n" +"non-literal strings." +msgstr "" + +#: src\idioms/concat-format.md:12 +msgid "" +"```rust\n" +"fn say_hello(name: &str) -> String {\n" +" // We could construct the result string manually.\n" +" // let mut result = \"Hello \".to_owned();\n" +" // result.push_str(name);\n" +" // result.push('!');\n" +" // result\n" +"\n" +" // But using format! is better.\n" +" format!(\"Hello {}!\", name)\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/concat-format.md:25 src\idioms/deref.md:43 +#: src\idioms/dtor-finally.md:42 src\idioms/mem-replace.md:83 +#: src\idioms/on-stack-dyn-dispatch.md:48 src\idioms/ffi/errors.md:131 +#: src\idioms/ffi/accepting-strings.md:68 src\idioms/ffi/passing-strings.md:68 +#: src\idioms/pass-var-to-closure.md:48 src\idioms/temporary-mutability.md:38 +#: src\idioms/return-consumed-arg-on-error.md:55 +#: src\patterns/behavioural/newtype.md:66 src\patterns/behavioural/RAII.md:78 +#: src\patterns/behavioural/strategy.md:96 +#: src\patterns/creational/builder.md:68 +#: src\patterns/structural/compose-structs.md:75 +#: src\patterns/structural/small-crates.md:12 +#: src\patterns/structural/unsafe-mods.md:11 src\patterns/ffi/export.md:111 +#: src\patterns/ffi/wrappers.md:63 src\anti_patterns/deny-warnings.md:16 +#: src\anti_patterns/deref.md:69 src\functional/generics-type-classes.md:210 +msgid "## Advantages" +msgstr "" + +#: src\idioms/concat-format.md:27 +msgid "" +"Using `format!` is usually the most succinct and readable way to combine " +"strings." +msgstr "" + +#: src\idioms/concat-format.md:29 src\idioms/deref.md:50 +#: src\idioms/dtor-finally.md:47 src\idioms/mem-replace.md:87 +#: src\idioms/on-stack-dyn-dispatch.md:54 src\idioms/ffi/errors.md:136 +#: src\idioms/ffi/accepting-strings.md:141 +#: src\idioms/ffi/passing-strings.md:103 src\idioms/pass-var-to-closure.md:57 +#: src\idioms/temporary-mutability.md:42 +#: src\idioms/return-consumed-arg-on-error.md:59 +#: src\patterns/behavioural/newtype.md:77 +#: src\patterns/behavioural/strategy.md:104 +#: src\patterns/creational/builder.md:76 +#: src\patterns/structural/compose-structs.md:81 +#: src\patterns/structural/small-crates.md:22 +#: src\patterns/structural/unsafe-mods.md:17 src\patterns/ffi/export.md:234 +#: src\patterns/ffi/wrappers.md:69 src\anti_patterns/deref.md:81 +#: src\functional/generics-type-classes.md:221 +msgid "## Disadvantages" +msgstr "" + +#: src\idioms/concat-format.md:31 +msgid "" +"It is usually not the most efficient way to combine strings - a series of " +"`push`\n" +"operations on a mutable string is usually the most efficient (especially if " +"the\n" +"string has been pre-allocated to the expected size)." +msgstr "" + +#: src\idioms/ctor.md:1 +msgid "# Constructors\r" +msgstr "" + +#: src\idioms/ctor.md:3 src\idioms/rustdoc-init.md:3 +msgid "## Description\r" +msgstr "" + +#: src\idioms/ctor.md:5 +msgid "" +"Rust does not have constructors as a language construct. Instead, the\r\n" +"convention is to use an [associated function][associated function] `new` to " +"create an object:" +msgstr "" + +#: src\idioms/ctor.md:8 +msgid "" +"````rust\r\n" +"/// Time in seconds.\r\n" +"///\r\n" +"/// # Example\r\n" +"///\r\n" +"/// ```\r\n" +"/// let s = Second::new(42);\r\n" +"/// assert_eq!(42, s.value());\r\n" +"/// ```\r\n" +"pub struct Second {\r\n" +" value: u64\r\n" +"}\r\n" +"\r\n" +"impl Second {\r\n" +" // Constructs a new instance of [`Second`].\r\n" +" // Note this is an associated function - no self.\r\n" +" pub fn new(value: u64) -> Self {\r\n" +" Self { value }\r\n" +" }\r\n" +"\r\n" +" /// Returns the value in seconds.\r\n" +" pub fn value(&self) -> u64 {\r\n" +" self.value\r\n" +" }\r\n" +"}\r\n" +"````" +msgstr "" + +#: src\idioms/ctor.md:35 +msgid "## Default Constructors\r" +msgstr "" + +#: src\idioms/ctor.md:37 +msgid "" +"Rust supports default constructors with the [`Default`][std-default] trait:" +msgstr "" + +#: src\idioms/ctor.md:39 +msgid "" +"````rust\r\n" +"/// Time in seconds.\r\n" +"///\r\n" +"/// # Example\r\n" +"///\r\n" +"/// ```\r\n" +"/// let s = Second::default();\r\n" +"/// assert_eq!(0, s.value());\r\n" +"/// ```\r\n" +"pub struct Second {\r\n" +" value: u64\r\n" +"}\r\n" +"\r\n" +"impl Second {\r\n" +" /// Returns the value in seconds.\r\n" +" pub fn value(&self) -> u64 {\r\n" +" self.value\r\n" +" }\r\n" +"}\r\n" +"\r\n" +"impl Default for Second {\r\n" +" fn default() -> Self {\r\n" +" Self { value: 0 }\r\n" +" }\r\n" +"}\r\n" +"````" +msgstr "" + +#: src\idioms/ctor.md:66 +msgid "" +"`Default` can also be derived if all types of all fields implement `Default`," +"\r\n" +"like they do with `Second`:" +msgstr "" + +#: src\idioms/ctor.md:69 +msgid "" +"````rust\r\n" +"/// Time in seconds.\r\n" +"///\r\n" +"/// # Example\r\n" +"///\r\n" +"/// ```\r\n" +"/// let s = Second::default();\r\n" +"/// assert_eq!(0, s.value());\r\n" +"/// ```\r\n" +"#[derive(Default)]\r\n" +"pub struct Second {\r\n" +" value: u64\r\n" +"}\r\n" +"\r\n" +"impl Second {\r\n" +" /// Returns the value in seconds.\r\n" +" pub fn value(&self) -> u64 {\r\n" +" self.value\r\n" +" }\r\n" +"}\r\n" +"````" +msgstr "" + +#: src\idioms/ctor.md:91 +msgid "" +"**Note:** It is common and expected for types to implement both\r\n" +"`Default` and an empty `new` constructor. `new` is the constructor\r\n" +"convention in Rust, and users expect it to exist, so if it is\r\n" +"reasonable for the basic constructor to take no arguments, then it\r\n" +"should, even if it is functionally identical to default." +msgstr "" + +#: src\idioms/ctor.md:97 +msgid "" +"**Hint:** The advantage of implementing or deriving `Default` is that your " +"type\r\n" +"can now be used where a `Default` implementation is required, most " +"prominently,\r\n" +"any of the [`*or_default` functions in the standard library][std-or-default]." +msgstr "" + +#: src\idioms/ctor.md:101 +msgid "## See also\r" +msgstr "" + +#: src\idioms/ctor.md:103 +msgid "" +"- The [default idiom](default.md) for a more in-depth description of the\r\n" +" `Default` trait.\r\n" +"\r\n" +"- The [builder pattern](../patterns/creational/builder.md) for " +"constructing\r\n" +" objects where there are multiple configurations.\r\n" +"\r\n" +"- [API Guidelines/C-COMMON-TRAITS][API Guidelines/C-COMMON-TRAITS] for\r\n" +" implementing both, `Default` and `new`.\r\n" +"\r" +msgstr "" + +#: src\idioms/default.md:1 +msgid "# The `Default` Trait" +msgstr "" + +#: src\idioms/default.md:5 +msgid "" +"Many types in Rust have a [constructor]. However, this is _specific_ to the\n" +"type; Rust cannot abstract over \"everything that has a `new()` method\". " +"To\n" +"allow this, the [`Default`] trait was conceived, which can be used with\n" +"containers and other generic types (e.g. see " +"[`Option::unwrap_or_default()`]).\n" +"Notably, some containers already implement it where applicable." +msgstr "" + +#: src\idioms/default.md:11 +msgid "" +"Not only do one-element containers like `Cow`, `Box` or `Arc` implement\n" +"`Default` for contained `Default` types, one can automatically\n" +"`#[derive(Default)]` for structs whose fields all implement it, so the more\n" +"types implement `Default`, the more useful it becomes." +msgstr "" + +#: src\idioms/default.md:16 +msgid "" +"On the other hand, constructors can take multiple arguments, while the\n" +"`default()` method does not. There can even be multiple constructors with\n" +"different names, but there can only be one `Default` implementation per type." +msgstr "" + +#: src\idioms/default.md:22 +msgid "" +"```rust\n" +"use std::{path::PathBuf, time::Duration};\n" +"\n" +"// note that we can simply auto-derive Default here.\n" +"#[derive(Default, Debug, PartialEq)]\n" +"struct MyConfiguration {\n" +" // Option defaults to None\n" +" output: Option,\n" +" // Vecs default to empty vector\n" +" search_path: Vec,\n" +" // Duration defaults to zero time\n" +" timeout: Duration,\n" +" // bool defaults to false\n" +" check: bool,\n" +"}\n" +"\n" +"impl MyConfiguration {\n" +" // add setters here\n" +"}\n" +"\n" +"fn main() {\n" +" // construct a new instance with default values\n" +" let mut conf = MyConfiguration::default();\n" +" // do something with conf here\n" +" conf.check = true;\n" +" println!(\"conf = {:#?}\", conf);\n" +" \n" +" // partial initialization with default values, creates the same " +"instance\n" +" let conf1 = MyConfiguration {\n" +" check: true,\n" +" ..Default::default()\n" +" };\n" +" assert_eq!(conf, conf1);\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/default.md:60 +msgid "" +"- The [constructor] idiom is another way to generate instances that may or " +"may\n" +" not be \"default\"\n" +"- The [`Default`] documentation (scroll down for the list of implementors)\n" +"- [`Option::unwrap_or_default()`]\n" +"- [`derive(new)`]" +msgstr "" + +#: src\idioms/deref.md:1 +msgid "# Collections are smart pointers" +msgstr "" + +#: src\idioms/deref.md:5 +msgid "" +"Use the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\n" +"trait to treat collections like smart pointers, offering owning\n" +"and borrowed views of data." +msgstr "" + +#: src\idioms/deref.md:11 +msgid "" +"```rust,ignore\n" +"use std::ops::Deref;\n" +"\n" +"struct Vec {\n" +" data: RawVec,\n" +" //..\n" +"}\n" +"\n" +"impl Deref for Vec {\n" +" type Target = [T];\n" +"\n" +" fn deref(&self) -> &[T] {\n" +" //..\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/deref.md:28 +msgid "" +"A `Vec` is an owning collection of `T`s, while a slice (`&[T]`) is a " +"borrowed\n" +"collection of `T`s. Implementing `Deref` for `Vec` allows implicit " +"dereferencing\n" +"from `&Vec` to `&[T]` and includes the relationship in auto-derefencing\n" +"searches. Most methods you might expect to be implemented for `Vec`s are " +"instead\n" +"implemented for slices." +msgstr "" + +#: src\idioms/deref.md:34 +msgid "Also `String` and `&str` have a similar relation." +msgstr "" + +#: src\idioms/deref.md:36 src\idioms/dtor-finally.md:32 +#: src\idioms/mem-replace.md:57 src\idioms/on-stack-dyn-dispatch.md:37 +#: src\idioms/ffi/accepting-strings.md:12 src\idioms/ffi/passing-strings.md:14 +#: src\idioms/return-consumed-arg-on-error.md:43 +#: src\patterns/behavioural/command.md:8 +#: src\patterns/behavioural/interpreter.md:16 +#: src\patterns/behavioural/newtype.md:56 src\patterns/behavioural/RAII.md:72 +#: src\patterns/behavioural/strategy.md:19 +#: src\patterns/behavioural/visitor.md:72 src\patterns/creational/builder.md:63 +#: src\patterns/creational/fold.md:73 +#: src\patterns/structural/compose-structs.md:71 src\patterns/ffi/export.md:15 +#: src\anti_patterns/borrow_clone.md:30 +msgid "## Motivation" +msgstr "" + +#: src\idioms/deref.md:38 +msgid "" +"Ownership and borrowing are key aspects of the Rust language. Data " +"structures\n" +"must account for these semantics properly to give a good user\n" +"experience. When implementing a data structure that owns its data, offering " +"a\n" +"borrowed view of that data allows for more flexible APIs." +msgstr "" + +#: src\idioms/deref.md:45 +msgid "" +"Most methods can be implemented only for the borrowed view, they are then\n" +"implicitly available for the owning view." +msgstr "" + +#: src\idioms/deref.md:48 +msgid "Gives clients a choice between borrowing or taking ownership of data." +msgstr "" + +#: src\idioms/deref.md:52 +msgid "" +"Methods and traits only available via dereferencing are not taken into " +"account\n" +"when bounds checking, so generic programming with data structures using " +"this\n" +"pattern can get complex (see the `Borrow` and `AsRef` traits, etc.)." +msgstr "" + +#: src\idioms/deref.md:56 src\idioms/dtor-finally.md:61 +#: src\idioms/mem-replace.md:97 src\idioms/on-stack-dyn-dispatch.md:68 +#: src\idioms/priv-extend.md:85 src\patterns/behavioural/command.md:203 +#: src\patterns/behavioural/interpreter.md:103 +#: src\patterns/behavioural/newtype.md:85 src\patterns/behavioural/RAII.md:83 +#: src\patterns/behavioural/strategy.md:110 +#: src\patterns/behavioural/visitor.md:79 src\patterns/creational/builder.md:81 +#: src\patterns/creational/fold.md:85 +#: src\patterns/structural/compose-structs.md:89 src\anti_patterns/deref.md:102 +msgid "## Discussion" +msgstr "" + +#: src\idioms/deref.md:58 +msgid "" +"Smart pointers and collections are analogous: a smart pointer points to a " +"single\n" +"object, whereas a collection points to many objects. From the point of view " +"of\n" +"the type system, there is little difference between the two. A collection " +"owns\n" +"its data if the only way to access each datum is via the collection and the\n" +"collection is responsible for deleting the data (even in cases of shared\n" +"ownership, some kind of borrowed view may be appropriate). If a collection " +"owns\n" +"its data, it is usually useful to provide a view of the data as borrowed so " +"that\n" +"it can be referenced multiple times." +msgstr "" + +#: src\idioms/deref.md:67 +msgid "" +"Most smart pointers (e.g., `Foo`) implement `Deref`. However,\n" +"collections will usually dereference to a custom type. `[T]` and `str` have " +"some\n" +"language support, but in the general case, this is not necessary. `Foo` " +"can\n" +"implement `Deref>` where `Bar` is a dynamically sized type " +"and\n" +"`&Bar` is a borrowed view of the data in `Foo`." +msgstr "" + +#: src\idioms/deref.md:73 +msgid "" +"Commonly, ordered collections will implement `Index` for `Range`s to " +"provide\n" +"slicing syntax. The target will be the borrowed view." +msgstr "" + +#: src\idioms/deref.md:78 +msgid "" +"- [Deref polymorphism anti-pattern](../anti_patterns/deref.md).\n" +"- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" +"trait.Deref.html)." +msgstr "" + +#: src\idioms/dtor-finally.md:1 +msgid "# Finalisation in destructors" +msgstr "" + +#: src\idioms/dtor-finally.md:5 +msgid "" +"Rust does not provide the equivalent to `finally` blocks - code that will " +"be\n" +"executed no matter how a function is exited. Instead, an object's destructor " +"can\n" +"be used to run code that must be run before exit." +msgstr "" + +#: src\idioms/dtor-finally.md:11 +msgid "" +"```rust,ignore\n" +"fn bar() -> Result<(), ()> {\n" +" // These don't need to be defined inside the function.\n" +" struct Foo;\n" +"\n" +" // Implement a destructor for Foo.\n" +" impl Drop for Foo {\n" +" fn drop(&mut self) {\n" +" println!(\"exit\");\n" +" }\n" +" }\n" +"\n" +" // The dtor of _exit will run however the function `bar` is exited.\n" +" let _exit = Foo;\n" +" // Implicit return with `?` operator.\n" +" baz()?;\n" +" // Normal return.\n" +" Ok(())\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/dtor-finally.md:34 +msgid "" +"If a function has multiple return points, then executing code on exit " +"becomes\n" +"difficult and repetitive (and thus bug-prone). This is especially the case " +"where\n" +"return is implicit due to a macro. A common case is the `?` operator which\n" +"returns if the result is an `Err`, but continues if it is `Ok`. `?` is used " +"as\n" +"an exception handling mechanism, but unlike Java (which has `finally`), " +"there is\n" +"no way to schedule code to run in both the normal and exceptional cases.\n" +"Panicking will also exit a function early." +msgstr "" + +#: src\idioms/dtor-finally.md:44 +msgid "" +"Code in destructors will (nearly) always be run - copes with panics, early\n" +"returns, etc." +msgstr "" + +#: src\idioms/dtor-finally.md:49 +msgid "" +"It is not guaranteed that destructors will run. For example, if there is an\n" +"infinite loop in a function or if running a function crashes before exit.\n" +"Destructors are also not run in the case of a panic in an already panicking\n" +"thread. Therefore, destructors cannot be relied on as finalizers where it " +"is\n" +"absolutely essential that finalisation happens." +msgstr "" + +#: src\idioms/dtor-finally.md:55 +msgid "" +"This pattern introduces some hard to notice, implicit code. Reading a " +"function\n" +"gives no clear indication of destructors to be run on exit. This can make\n" +"debugging tricky." +msgstr "" + +#: src\idioms/dtor-finally.md:59 +msgid "" +"Requiring an object and `Drop` impl just for finalisation is heavy on " +"boilerplate." +msgstr "" + +#: src\idioms/dtor-finally.md:63 +msgid "" +"There is some subtlety about how exactly to store the object used as a\n" +"finalizer. It must be kept alive until the end of the function and must then " +"be\n" +"destroyed. The object must always be a value or uniquely owned pointer " +"(e.g.,\n" +"`Box`). If a shared pointer (such as `Rc`) is used, then the finalizer " +"can\n" +"be kept alive beyond the lifetime of the function. For similar reasons, the\n" +"finalizer should not be moved or returned." +msgstr "" + +#: src\idioms/dtor-finally.md:70 +msgid "" +"The finalizer must be assigned into a variable, otherwise it will be " +"destroyed\n" +"immediately, rather than when it goes out of scope. The variable name must " +"start\n" +"with `_` if the variable is only used as a finalizer, otherwise the " +"compiler\n" +"will warn that the finalizer is never used. However, do not call the " +"variable\n" +"`_` with no suffix - in that case it will be destroyed immediately." +msgstr "" + +#: src\idioms/dtor-finally.md:76 +msgid "" +"In Rust, destructors are run when an object goes out of scope. This happens\n" +"whether we reach the end of block, there is an early return, or the program\n" +"panics. When panicking, Rust unwinds the stack running destructors for each\n" +"object in each stack frame. So, destructors get called even if the panic " +"happens\n" +"in a function being called." +msgstr "" + +#: src\idioms/dtor-finally.md:82 +msgid "" +"If a destructor panics while unwinding, there is no good action to take, so " +"Rust\n" +"aborts the thread immediately, without running further destructors. This " +"means\n" +"that destructors are not absolutely guaranteed to run. It also means that " +"you\n" +"must take extra care in your destructors not to panic, since it could leave\n" +"resources in an unexpected state." +msgstr "" + +#: src\idioms/dtor-finally.md:90 +msgid "[RAII guards](../patterns/behavioural/RAII.md)." +msgstr "" + +#: src\idioms/mem-replace.md:1 +msgid "# `mem::{take(_), replace(_)}` to keep owned values in changed enums" +msgstr "" + +#: src\idioms/mem-replace.md:5 +msgid "" +"Say we have a `&mut MyEnum` which has (at least) two variants,\n" +"`A { name: String, x: u8 }` and `B { name: String }`. Now we want to change\n" +"`MyEnum::A` to a `B` if `x` is zero, while keeping `MyEnum::B` intact." +msgstr "" + +#: src\idioms/mem-replace.md:9 +msgid "We can do this without cloning the `name`." +msgstr "" + +#: src\idioms/mem-replace.md:13 +msgid "" +"```rust\n" +"use std::mem;\n" +"\n" +"enum MyEnum {\n" +" A { name: String, x: u8 },\n" +" B { name: String }\n" +"}\n" +"\n" +"fn a_to_b(e: &mut MyEnum) {\n" +" if let MyEnum::A { name, x: 0 } = e {\n" +" // this takes out our `name` and put in an empty String instead\n" +" // (note that empty strings don't allocate).\n" +" // Then, construct the new enum variant (which will\n" +" // be assigned to `*e`).\n" +" *e = MyEnum::B { name: mem::take(name) }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/mem-replace.md:32 +msgid "This also works with more variants:" +msgstr "" + +#: src\idioms/mem-replace.md:34 +msgid "" +"```rust\n" +"use std::mem;\n" +"\n" +"enum MultiVariateEnum {\n" +" A { name: String },\n" +" B { name: String },\n" +" C,\n" +" D\n" +"}\n" +"\n" +"fn swizzle(e: &mut MultiVariateEnum) {\n" +" use MultiVariateEnum::*;\n" +" *e = match e {\n" +" // Ownership rules do not allow taking `name` by value, but we " +"cannot\n" +" // take the value out of a mutable reference, unless we replace it:\n" +" A { name } => B { name: mem::take(name) },\n" +" B { name } => A { name: mem::take(name) },\n" +" C => D,\n" +" D => C\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/mem-replace.md:59 +msgid "" +"When working with enums, we may want to change an enum value in place, " +"perhaps\n" +"to another variant. This is usually done in two phases to keep the borrow\n" +"checker happy. In the first phase, we observe the existing value and look " +"at\n" +"its parts to decide what to do next. In the second phase we may " +"conditionally\n" +"change the value (as in the example above)." +msgstr "" + +#: src\idioms/mem-replace.md:65 +msgid "" +"The borrow checker won't allow us to take out `name` of the enum (because\n" +"_something_ must be there.) We could of course `.clone()` name and put the " +"clone\n" +"into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy " +"the borrow checker](../anti_patterns/borrow_clone.md) anti-pattern. Anyway, " +"we\n" +"can avoid the extra allocation by changing `e` with only a mutable borrow." +msgstr "" + +#: src\idioms/mem-replace.md:70 +msgid "" +"`mem::take` lets us swap out the value, replacing it with it's default " +"value,\n" +"and returning the previous value. For `String`, the default value is an " +"empty\n" +"`String`, which does not need to allocate. As a result, we get the original\n" +"`name` _as an owned value_. We can then wrap this in another enum." +msgstr "" + +#: src\idioms/mem-replace.md:75 +msgid "" +"**NOTE:** `mem::replace` is very similar, but allows us to specify what to\n" +"replace the value with. An equivalent to our `mem::take` line would be\n" +"`mem::replace(name, String::new())`." +msgstr "" + +#: src\idioms/mem-replace.md:79 +msgid "" +"Note, however, that if we are using an `Option` and want to replace its\n" +"value with a `None`, `Option`’s `take()` method provides a shorter and\n" +"more idiomatic alternative." +msgstr "" + +#: src\idioms/mem-replace.md:85 +msgid "" +"Look ma, no allocation! Also you may feel like Indiana Jones while doing it." +msgstr "" + +#: src\idioms/mem-replace.md:89 +msgid "" +"This gets a bit wordy. Getting it wrong repeatedly will make you hate the\n" +"borrow checker. The compiler may fail to optimize away the double store,\n" +"resulting in reduced performance as opposed to what you'd do in unsafe\n" +"languages." +msgstr "" + +#: src\idioms/mem-replace.md:94 +msgid "" +"Furthermore, the type you are taking needs to implement the [`Default` trait]" +"(./default.md). However, if the type you're working with doesn't\n" +"implement this, you can instead use `mem::replace`." +msgstr "" + +#: src\idioms/mem-replace.md:99 +msgid "" +"This pattern is only of interest in Rust. In GC'd languages, you'd take the\n" +"reference to the value by default (and the GC would keep track of refs), and " +"in\n" +"other low-level languages like C you'd simply alias the pointer and fix " +"things\n" +"later." +msgstr "" + +#: src\idioms/mem-replace.md:104 +msgid "" +"However, in Rust, we have to do a little more work to do this. An owned " +"value\n" +"may only have one owner, so to take it out, we need to put something back in " +"–\n" +"like Indiana Jones, replacing the artifact with a bag of sand." +msgstr "" + +#: src\idioms/mem-replace.md:110 +msgid "" +"This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/" +"borrow_clone.md)\n" +"anti-pattern in a specific case." +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:1 +msgid "# On-Stack Dynamic Dispatch" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:5 +msgid "" +"We can dynamically dispatch over multiple values, however, to do so, we " +"need\n" +"to declare multiple variables to bind differently-typed objects. To extend " +"the\n" +"lifetime as necessary, we can use deferred conditional initialization, as " +"seen\n" +"below:" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:12 +msgid "" +"```rust\n" +"use std::io;\n" +"use std::fs;\n" +"\n" +"# fn main() -> Result<(), Box> {\n" +"# let arg = \"-\";\n" +"\n" +"// These must live longer than `readable`, and thus are declared first:\n" +"let (mut stdin_read, mut file_read);\n" +"\n" +"// We need to ascribe the type to get dynamic dispatch.\n" +"let readable: &mut dyn io::Read = if arg == \"-\" {\n" +" stdin_read = io::stdin();\n" +" &mut stdin_read\n" +"} else {\n" +" file_read = fs::File::open(arg)?;\n" +" &mut file_read\n" +"};\n" +"\n" +"// Read from `readable` here.\n" +"\n" +"# Ok(())\n" +"# }\n" +"```" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:39 +msgid "" +"Rust monomorphises code by default. This means a copy of the code will be\n" +"generated for each type it is used with and optimized independently. While " +"this\n" +"allows for very fast code on the hot path, it also bloats the code in " +"places\n" +"where performance is not of the essence, thus costing compile time and " +"cache\n" +"usage." +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:45 +msgid "" +"Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " +"ask\n" +"for it." +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:50 +msgid "" +"We do not need to allocate anything on the heap. Neither do we need to\n" +"initialize something we won't use later, nor do we need to monomorphize the\n" +"whole code that follows to work with both `File` or `Stdin`." +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:56 +msgid "The code needs more moving parts than the `Box`-based version:" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:58 +msgid "" +"```rust,ignore\n" +"// We still need to ascribe the type for dynamic dispatch.\n" +"let readable: Box = if arg == \"-\" {\n" +" Box::new(io::stdin())\n" +"} else {\n" +" Box::new(fs::File::open(arg)?)\n" +"};\n" +"// Read from `readable` here.\n" +"```" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:70 +msgid "" +"Rust newcomers will usually learn that Rust requires all variables to be\n" +"initialized _before use_, so it's easy to overlook the fact that _unused_\n" +"variables may well be uninitialized. Rust works quite hard to ensure that " +"this\n" +"works out fine and only the initialized values are dropped at the end of " +"their\n" +"scope." +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:76 +msgid "The example meets all the constraints Rust places on us:" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:78 +msgid "" +"- All variables are initialized before using (in this case borrowing) them\n" +"- Each variable only holds values of a single type. In our example, `stdin` " +"is\n" +" of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut " +"dyn Read`\n" +"- Each borrowed value outlives all the references borrowed from it" +msgstr "" + +#: src\idioms/on-stack-dyn-dispatch.md:85 +msgid "" +"- [Finalisation in destructors](dtor-finally.md) and\n" +" [RAII guards](../patterns/behavioural/RAII.md) can benefit from tight " +"control over\n" +" lifetimes.\n" +"- For conditionally filled `Option<&T>`s of (mutable) references, one can\n" +" initialize an `Option` directly and use its [`.as_ref()`] method to get " +"an\n" +" optional reference." +msgstr "" + +#: src\idioms/ffi/intro.md:1 +msgid "# FFI Idioms" +msgstr "" + +#: src\idioms/ffi/intro.md:3 +msgid "" +"Writing FFI code is an entire course in itself.\n" +"However, there are several idioms here that can act as pointers, and avoid\n" +"traps for inexperienced users of `unsafe` Rust." +msgstr "" + +#: src\idioms/ffi/intro.md:7 +msgid "This section contains idioms that may be useful when doing FFI." +msgstr "" + +#: src\idioms/ffi/intro.md:9 +msgid "" +"1. [Idiomatic Errors](./errors.md) - Error handling with integer codes and\n" +" sentinel return values (such as `NULL` pointers)\n" +"\n" +"2. [Accepting Strings](./accepting-strings.md) with minimal unsafe code\n" +"\n" +"3. [Passing Strings](./passing-strings.md) to FFI functions" +msgstr "" + +#: src\idioms/ffi/errors.md:1 +msgid "# Error Handling in FFI" +msgstr "" + +#: src\idioms/ffi/errors.md:5 +msgid "" +"In foreign languages like C, errors are represented by return codes.\n" +"However, Rust's type system allows much more rich error information to be\n" +"captured and propogated through a full type." +msgstr "" + +#: src\idioms/ffi/errors.md:9 +msgid "" +"This best practice shows different kinds of error codes, and how to expose " +"them\n" +"in a usable way:" +msgstr "" + +#: src\idioms/ffi/errors.md:12 +msgid "" +"1. Flat Enums should be converted to integers and returned as codes.\n" +"2. Structured Enums should be converted to an integer code with a string " +"error\n" +" message for detail.\n" +"3. Custom Error Types should become \"transparent\", with a C representation." +msgstr "" + +#: src\idioms/ffi/errors.md:17 src\idioms/ffi/accepting-strings.md:29 +#: src\idioms/ffi/passing-strings.md:26 src\patterns/ffi/export.md:40 +#: src\patterns/ffi/wrappers.md:23 +msgid "## Code Example" +msgstr "" + +#: src\idioms/ffi/errors.md:19 +msgid "### Flat Enums" +msgstr "" + +#: src\idioms/ffi/errors.md:21 +msgid "" +"```rust,ignore\n" +"enum DatabaseError {\n" +" IsReadOnly = 1, // user attempted a write operation\n" +" IOError = 2, // user should read the C errno() for what it was\n" +" FileCorrupted = 3, // user should run a repair tool to recover it\n" +"}\n" +"\n" +"impl From for libc::c_int {\n" +" fn from(e: DatabaseError) -> libc::c_int {\n" +" (e as i8).into()\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/errors.md:35 +msgid "### Structured Enums" +msgstr "" + +#: src\idioms/ffi/errors.md:37 +msgid "" +"```rust,ignore\n" +"pub mod errors {\n" +" enum DatabaseError {\n" +" IsReadOnly,\n" +" IOError(std::io::Error),\n" +" FileCorrupted(String), // message describing the issue\n" +" }\n" +"\n" +" impl From for libc::c_int {\n" +" fn from(e: DatabaseError) -> libc::c_int {\n" +" match e {\n" +" DatabaseError::IsReadOnly => 1,\n" +" DatabaseError::IOError(_) => 2,\n" +" DatabaseError::FileCorrupted(_) => 3,\n" +" }\n" +" }\n" +" }\n" +"}\n" +"\n" +"pub mod c_api {\n" +" use super::errors::DatabaseError;\n" +"\n" +" #[no_mangle]\n" +" pub extern \"C\" fn db_error_description(\n" +" e: *const DatabaseError\n" +" ) -> *mut libc::c_char {\n" +"\n" +" let error: &DatabaseError = unsafe {\n" +" // SAFETY: pointer lifetime is greater than the current stack " +"frame\n" +" &*e\n" +" };\n" +"\n" +" let error_str: String = match error {\n" +" DatabaseError::IsReadOnly => {\n" +" format!(\"cannot write to read-only database\");\n" +" }\n" +" DatabaseError::IOError(e) => {\n" +" format!(\"I/O Error: {}\", e);\n" +" }\n" +" DatabaseError::FileCorrupted(s) => {\n" +" format!(\"File corrupted, run repair: {}\", &s);\n" +" }\n" +" };\n" +"\n" +" let c_error = unsafe {\n" +" // SAFETY: copying error_str to an allocated buffer with a NUL\n" +" // character at the end\n" +" let mut malloc: *mut u8 = libc::malloc(error_str.len() + 1) as " +"*mut _;\n" +"\n" +" if malloc.is_null() {\n" +" return std::ptr::null_mut();\n" +" }\n" +"\n" +" let src = error_str.as_bytes().as_ptr();\n" +"\n" +" std::ptr::copy_nonoverlapping(src, malloc, error_str.len());\n" +"\n" +" std::ptr::write(malloc.add(error_str.len()), 0);\n" +"\n" +" malloc as *mut libc::c_char\n" +" };\n" +"\n" +" c_error\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/errors.md:104 +msgid "### Custom Error Types" +msgstr "" + +#: src\idioms/ffi/errors.md:106 +msgid "" +"```rust,ignore\n" +"struct ParseError {\n" +" expected: char,\n" +" line: u32,\n" +" ch: u16\n" +"}\n" +"\n" +"impl ParseError { /* ... */ }\n" +"\n" +"/* Create a second version which is exposed as a C structure */\n" +"#[repr(C)]\n" +"pub struct parse_error {\n" +" pub expected: libc::c_char,\n" +" pub line: u32,\n" +" pub ch: u16\n" +"}\n" +"\n" +"impl From for parse_error {\n" +" fn from(e: ParseError) -> parse_error {\n" +" let ParseError { expected, line, ch } = e;\n" +" parse_error { expected, line, ch }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/errors.md:133 +msgid "" +"This ensures that the foreign language has clear access to error " +"information\n" +"while not compromising the Rust code's API at all." +msgstr "" + +#: src\idioms/ffi/errors.md:138 +msgid "" +"It's a lot of typing, and some types may not be able to be converted easily\n" +"to C." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:1 +msgid "# Accepting Strings" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:5 +msgid "" +"When accepting strings via FFI through pointers, there are two principles " +"that\n" +"should be followed:" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:8 +msgid "" +"1. Keep foreign strings \"borrowed\", rather than copying them directly.\n" +"2. Minimize the amount of complexity and `unsafe` code involved in " +"converting\n" +" from a C-style string to native Rust strings." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:14 +msgid "" +"The strings used in C have different behaviours to those used in Rust, " +"namely:" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:16 +msgid "" +"- C strings are null-terminated while Rust strings store their length\n" +"- C strings can contain any arbitrary non-zero byte while Rust strings must " +"be\n" +" UTF-8\n" +"- C strings are accessed and manipulated using `unsafe` pointer operations\n" +" while interactions with Rust strings go through safe methods" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:22 +msgid "" +"The Rust standard library comes with C equivalents of Rust's `String` and " +"`&str`\n" +"called `CString` and `&CStr`, that allow us to avoid a lot of the " +"complexity\n" +"and `unsafe` code involved in converting between C strings and Rust strings." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:26 +msgid "" +"The `&CStr` type also allows us to work with borrowed data, meaning passing\n" +"strings between Rust and C is a zero-cost operation." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:31 +msgid "" +"```rust,ignore\n" +"pub mod unsafe_module {\n" +"\n" +" // other module content\n" +"\n" +" /// Log a message at the specified level.\n" +" ///\n" +" /// # Safety\n" +" ///\n" +" /// It is the caller's guarantee to ensure `msg`:\n" +" ///\n" +" /// - is not a null pointer\n" +" /// - points to valid, initialized data\n" +" /// - points to memory ending in a null byte\n" +" /// - won't be mutated for the duration of this function call\n" +" #[no_mangle]\n" +" pub unsafe extern \"C\" fn mylib_log(\n" +" msg: *const libc::c_char,\n" +" level: libc::c_int\n" +" ) {\n" +" let level: crate::LogLevel = match level { /* ... */ };\n" +"\n" +" // SAFETY: The caller has already guaranteed this is okay (see the\n" +" // `# Safety` section of the doc-comment).\n" +" let msg_str: &str = match std::ffi::CStr::from_ptr(msg).to_str() {\n" +" Ok(s) => s,\n" +" Err(e) => {\n" +" crate::log_error(\"FFI string conversion failed\");\n" +" return;\n" +" }\n" +" };\n" +"\n" +" crate::log(msg_str, level);\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:70 +msgid "The example is is written to ensure that:" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:72 +msgid "" +"1. The `unsafe` block is as small as possible.\n" +"2. The pointer with an \"untracked\" lifetime becomes a \"tracked\" shared\n" +" reference" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:76 +msgid "Consider an alternative, where the string is actually copied:" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:78 +msgid "" +"```rust,ignore\n" +"pub mod unsafe_module {\n" +"\n" +" // other module content\n" +"\n" +" pub extern \"C\" fn mylib_log(msg: *const libc::c_char, level: " +"libc::c_int) {\n" +" // DO NOT USE THIS CODE.\n" +" // IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG.\n" +"\n" +" let level: crate::LogLevel = match level { /* ... */ };\n" +"\n" +" let msg_len = unsafe { /* SAFETY: strlen is what it is, I guess? */\n" +" libc::strlen(msg)\n" +" };\n" +"\n" +" let mut msg_data = Vec::with_capacity(msg_len + 1);\n" +"\n" +" let msg_cstr: std::ffi::CString = unsafe {\n" +" // SAFETY: copying from a foreign pointer expected to live\n" +" // for the entire stack frame into owned memory\n" +" std::ptr::copy_nonoverlapping(msg, msg_data.as_mut(), msg_len);\n" +"\n" +" msg_data.set_len(msg_len + 1);\n" +"\n" +" std::ffi::CString::from_vec_with_nul(msg_data).unwrap()\n" +" }\n" +"\n" +" let msg_str: String = unsafe {\n" +" match msg_cstr.into_string() {\n" +" Ok(s) => s,\n" +" Err(e) => {\n" +" crate::log_error(\"FFI string conversion failed\");\n" +" return;\n" +" }\n" +" }\n" +" };\n" +"\n" +" crate::log(&msg_str, level);\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:120 +msgid "This code in inferior to the original in two respects:" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:122 +msgid "" +"1. There is much more `unsafe` code, and more importantly, more invariants " +"it\n" +" must uphold.\n" +"2. Due to the extensive arithmetic required, there is a bug in this version\n" +" that cases Rust `undefined behaviour`." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:127 +msgid "" +"The bug here is a simple mistake in pointer arithmetic: the string was " +"copied,\n" +"all `msg_len` bytes of it. However, the `NUL` terminator at the end was not." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:130 +msgid "" +"The Vector then had its size _set_ to the length of the _zero padded string_ " +"--\n" +"rather than _resized_ to it, which could have added a zero at the end.\n" +"As a result, the last byte in the Vector is uninitialized memory.\n" +"When the `CString` is created at the bottom of the block, its read of the\n" +"Vector will cause `undefined behaviour`!" +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:136 +msgid "" +"Like many such issues, this would be difficult issue to track down.\n" +"Sometimes it would panic because the string was not `UTF-8`, sometimes it " +"would\n" +"put a weird character at the end of the string, sometimes it would just\n" +"completely crash." +msgstr "" + +#: src\idioms/ffi/accepting-strings.md:143 +#: src\idioms/ffi/passing-strings.md:105 +msgid "None?" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:1 +msgid "# Passing Strings" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:5 +msgid "" +"When passing strings to FFI functions, there are four principles that should " +"be\n" +"followed:" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:8 +msgid "" +"1. Make the lifetime of owned strings as long as possible.\n" +"2. Minimize `unsafe` code during the conversion.\n" +"3. If the C code can modify the string data, use `Vec` instead of " +"`CString`.\n" +"4. Unless the Foreign Function API requires it, the ownership of the string\n" +" should not transfer to the callee." +msgstr "" + +#: src\idioms/ffi/passing-strings.md:16 +msgid "" +"Rust has built-in support for C-style strings with its `CString` and `CStr`\n" +"types. However, there are different approaches one can take with strings " +"that\n" +"are being sent to a foreign function call from a Rust function." +msgstr "" + +#: src\idioms/ffi/passing-strings.md:20 +msgid "" +"The best practice is simple: use `CString` in such a way as to minimize\n" +"`unsafe` code. However, a secondary caveat is that\n" +"_the object must live long enough_, meaning the lifetime should be " +"maximized.\n" +"In addition, the documentation explains that \"round-tripping\" a `CString` " +"after\n" +"modification is UB, so additional work is necessary in that case." +msgstr "" + +#: src\idioms/ffi/passing-strings.md:28 +msgid "" +"```rust,ignore\n" +"pub mod unsafe_module {\n" +"\n" +" // other module content\n" +"\n" +" extern \"C\" {\n" +" fn seterr(message: *const libc::c_char);\n" +" fn geterr(buffer: *mut libc::c_char, size: libc::c_int) -> " +"libc::c_int;\n" +" }\n" +"\n" +" fn report_error_to_ffi>(\n" +" err: S\n" +" ) -> Result<(), std::ffi::NulError>{\n" +" let c_err = std::ffi::CString::new(err.into())?;\n" +"\n" +" unsafe {\n" +" // SAFETY: calling an FFI whose documentation says the pointer " +"is\n" +" // const, so no modification should occur\n" +" seterr(c_err.as_ptr());\n" +" }\n" +"\n" +" Ok(())\n" +" // The lifetime of c_err continues until here\n" +" }\n" +"\n" +" fn get_error_from_ffi() -> Result {\n" +" let mut buffer = vec![0u8; 1024];\n" +" unsafe {\n" +" // SAFETY: calling an FFI whose documentation implies\n" +" // that the input need only live as long as the call\n" +" let written: usize = geterr(buffer.as_mut_ptr(), 1023).into();\n" +"\n" +" buffer.truncate(written + 1);\n" +" }\n" +"\n" +" std::ffi::CString::new(buffer).unwrap().into_string()\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:70 +msgid "The example is written in a way to ensure that:" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:72 +msgid "" +"1. The `unsafe` block is as small as possible.\n" +"2. The `CString` lives long enough.\n" +"3. Errors with typecasts are always propagated when possible." +msgstr "" + +#: src\idioms/ffi/passing-strings.md:76 +msgid "" +"A common mistake (so common it's in the documentation) is to not use the\n" +"variable in the first block:" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:79 +msgid "" +"```rust,ignore\n" +"pub mod unsafe_module {\n" +"\n" +" // other module content\n" +"\n" +" fn report_error>(err: S) -> Result<(), " +"std::ffi::NulError> {\n" +" unsafe {\n" +" // SAFETY: whoops, this contains a dangling pointer!\n" +" seterr(std::ffi::CString::new(err.into())?.as_ptr());\n" +" }\n" +" Ok(())\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/ffi/passing-strings.md:94 +msgid "" +"This code will result in a dangling pointer, because the lifetime of the\n" +"`CString` is not extended by the pointer creation, unlike if a reference " +"were\n" +"created." +msgstr "" + +#: src\idioms/ffi/passing-strings.md:98 +msgid "" +"Another issue frequently raised is that the initialization of a 1k vector " +"of\n" +"zeroes is \"slow\". However, recent versions of Rust actually optimize that\n" +"particular macro to a call to `zmalloc`, meaning it is as fast as the " +"operating\n" +"system's ability to return zeroed memory (which is quite fast)." +msgstr "" + +#: src\idioms/option-iter.md:1 +msgid "# Iterating over an `Option`" +msgstr "" + +#: src\idioms/option-iter.md:5 +msgid "" +"`Option` can be viewed as a container that contains either zero or one\n" +"element. In particular, it implements the `IntoIterator` trait, and as such\n" +"can be used with generic code that needs such a type." +msgstr "" + +#: src\idioms/option-iter.md:9 src\patterns/structural/small-crates.md:34 +#: src\patterns/structural/unsafe-mods.md:22 +msgid "## Examples" +msgstr "" + +#: src\idioms/option-iter.md:11 +msgid "" +"Since `Option` implements `IntoIterator`, it can be used as an argument to\n" +"[`.extend()`](https://doc.rust-lang.org/std/iter/" +"trait.Extend.html#tymethod.extend):" +msgstr "" + +#: src\idioms/option-iter.md:14 +msgid "" +"```rust\n" +"let turing = Some(\"Turing\");\n" +"let mut logicians = vec![\"Curry\", \"Kleene\", \"Markov\"];\n" +"\n" +"logicians.extend(turing);\n" +"\n" +"// equivalent to\n" +"if let Some(turing_inner) = turing {\n" +" logicians.push(turing_inner);\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/option-iter.md:26 +msgid "" +"If you need to tack an `Option` to the end of an existing iterator, you can\n" +"pass it to [`.chain()`](https://doc.rust-lang.org/std/iter/" +"trait.Iterator.html#method.chain):" +msgstr "" + +#: src\idioms/option-iter.md:29 +msgid "" +"```rust\n" +"let turing = Some(\"Turing\");\n" +"let logicians = vec![\"Curry\", \"Kleene\", \"Markov\"];\n" +"\n" +"for logician in logicians.iter().chain(turing.iter()) {\n" +" println!(\"{} is a logician\", logician);\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/option-iter.md:38 +msgid "" +"Note that if the `Option` is always `Some`, then it is more idiomatic to " +"use\n" +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) on the\n" +"element instead." +msgstr "" + +#: src\idioms/option-iter.md:42 +msgid "" +"Also, since `Option` implements `IntoIterator`, it's possible to iterate " +"over\n" +"it using a `for` loop. This is equivalent to matching it with `if let " +"Some(..)`,\n" +"and in most cases you should prefer the latter." +msgstr "" + +#: src\idioms/option-iter.md:48 +msgid "" +"- [`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) is " +"an\n" +" iterator which yields exactly one element. It's a more readable " +"alternative to\n" +" `Some(foo).into_iter()`.\n" +"\n" +"- [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/" +"trait.Iterator.html#method.filter_map)\n" +" is a version of [`Iterator::map`](https://doc.rust-lang.org/std/iter/" +"trait.Iterator.html#method.map),\n" +" specialized to mapping functions which return `Option`.\n" +"\n" +"- The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions\n" +" for converting an `Option` to a zero- or one-element slice.\n" +"\n" +"- [Documentation for `Option`](https://doc.rust-lang.org/std/option/" +"enum.Option.html)" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:1 +msgid "# Pass variables to closure" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:5 +msgid "" +"By default, closures capture their environment by borrowing. Or you can use\n" +"`move`-closure to move whole environment. However, often you want to move " +"just\n" +"some variables to closure, give it copy of some data, pass it by reference, " +"or\n" +"perform some other transformation." +msgstr "" + +#: src\idioms/pass-var-to-closure.md:10 +msgid "Use variable rebinding in separate scope for that." +msgstr "" + +#: src\idioms/pass-var-to-closure.md:14 +msgid "Use" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:16 +msgid "" +"```rust\n" +"use std::rc::Rc;\n" +"\n" +"let num1 = Rc::new(1);\n" +"let num2 = Rc::new(2);\n" +"let num3 = Rc::new(3);\n" +"let closure = {\n" +" // `num1` is moved\n" +" let num2 = num2.clone(); // `num2` is cloned\n" +" let num3 = num3.as_ref(); // `num3` is borrowed\n" +" move || {\n" +" *num1 + *num2 + *num3;\n" +" }\n" +"};\n" +"```" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:32 +msgid "instead of" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:34 +msgid "" +"```rust\n" +"use std::rc::Rc;\n" +"\n" +"let num1 = Rc::new(1);\n" +"let num2 = Rc::new(2);\n" +"let num3 = Rc::new(3);\n" +"\n" +"let num2_cloned = num2.clone();\n" +"let num3_borrowed = num3.as_ref();\n" +"let closure = move || {\n" +" *num1 + *num2_cloned + *num3_borrowed;\n" +"};\n" +"```" +msgstr "" + +#: src\idioms/pass-var-to-closure.md:50 +msgid "" +"Copied data are grouped together with closure definition, so their purpose " +"is\n" +"more clear, and they will be dropped immediately even if they are not " +"consumed\n" +"by closure." +msgstr "" + +#: src\idioms/pass-var-to-closure.md:54 +msgid "" +"Closure uses same variable names as surrounding code whether data are copied " +"or\n" +"moved." +msgstr "" + +#: src\idioms/pass-var-to-closure.md:59 +msgid "Additional indentation of closure body." +msgstr "" + +#: src\idioms/priv-extend.md:1 +msgid "# `#[non_exhaustive]` and private fields for extensibility" +msgstr "" + +#: src\idioms/priv-extend.md:5 +msgid "" +"A small set of scenarios exist where a library author may want to add " +"public\n" +"fields to a public struct or new variants to an enum without breaking " +"backwards\n" +"compatibility." +msgstr "" + +#: src\idioms/priv-extend.md:9 +msgid "Rust offers two solutions to this problem:" +msgstr "" + +#: src\idioms/priv-extend.md:11 +msgid "" +"- Use `#[non_exhaustive]` on `struct`s, `enum`s, and `enum` variants.\n" +" For extensive documentation on all the places where `#[non_exhaustive]` " +"can be\n" +" used, see [the docs](https://doc.rust-lang.org/reference/attributes/" +"type_system.html#the-non_exhaustive-attribute).\n" +"\n" +"- You may add a private field to a struct to prevent it from being directly\n" +" instantiated or matched against (see Alternative)" +msgstr "" + +#: src\idioms/priv-extend.md:20 +msgid "" +"```rust\n" +"mod a {\n" +" // Public struct.\n" +" #[non_exhaustive]\n" +" pub struct S {\n" +" pub foo: i32,\n" +" }\n" +" \n" +" #[non_exhaustive]\n" +" pub enum AdmitMoreVariants {\n" +" VariantA,\n" +" VariantB,\n" +" #[non_exhaustive]\n" +" VariantC { a: String }\n" +" }\n" +"}\n" +"\n" +"fn print_matched_variants(s: a::S) {\n" +" // Because S is `#[non_exhaustive]`, it cannot be named here and\n" +" // we must use `..` in the pattern.\n" +" let a::S { foo: _, ..} = s;\n" +" \n" +" let some_enum = a::AdmitMoreVariants::VariantA;\n" +" match some_enum {\n" +" a::AdmitMoreVariants::VariantA => println!(\"it's an A\"),\n" +" a::AdmitMoreVariants::VariantB => println!(\"it's a b\"),\n" +"\n" +" // .. required because this variant is non-exhaustive as well\n" +" a::AdmitMoreVariants::VariantC { a, .. } => println!(\"it's a c\"),\n" +"\n" +" // The wildcard match is required because more variants may be\n" +" // added in the future\n" +" _ => println!(\"it's a new variant\")\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/priv-extend.md:57 +msgid "## Alternative: `Private fields` for structs" +msgstr "" + +#: src\idioms/priv-extend.md:59 +msgid "" +"`#[non_exhaustive]` only works across crate boundaries.\n" +"Within a crate, the private field method may be used." +msgstr "" + +#: src\idioms/priv-extend.md:62 +msgid "" +"Adding a field to a struct is a mostly backwards compatible change.\n" +"However, if a client uses a pattern to deconstruct a struct instance, they\n" +"might name all the fields in the struct and adding a new one would break " +"that\n" +"pattern.\n" +"The client could name some fields and use `..` in the pattern, in which case " +"adding\n" +"another field is backwards compatible.\n" +"Making at least one of the struct's fields private forces clients to use the " +"latter\n" +"form of patterns, ensuring that the struct is future-proof." +msgstr "" + +#: src\idioms/priv-extend.md:71 +msgid "" +"The downside of this approach is that you might need to add an otherwise " +"unneeded\n" +"field to the struct.\n" +"You can use the `()` type so that there is no runtime overhead and prepend " +"`_` to\n" +"the field name to avoid the unused field warning." +msgstr "" + +#: src\idioms/priv-extend.md:76 +msgid "" +"```rust\n" +"pub struct S {\n" +" pub a: i32,\n" +" // Because `b` is private, you cannot match on `S` without using `..` " +"and `S`\n" +" // cannot be directly instantiated or matched against\n" +" _b: ()\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/priv-extend.md:87 +msgid "" +"On `struct`s, `#[non_exhaustive]` allows adding additional fields in a " +"backwards\n" +"compatible way.\n" +"It will also prevent clients from using the struct constructor, even if all " +"the\n" +"fields are public.\n" +"This may be helpful, but it's worth considering if you _want_ an additional " +"field\n" +"to be found by clients as a compiler error rather than something that may be " +"silently\n" +"undiscovered." +msgstr "" + +#: src\idioms/priv-extend.md:95 +msgid "" +"`#[non_exhaustive]` can be applied to enum variants as well.\n" +"A `#[non_exhaustive]` variant behaves in the same way as a " +"`#[non_exhaustive]` struct." +msgstr "" + +#: src\idioms/priv-extend.md:98 +msgid "" +"Use this deliberately and with caution: incrementing the major version when " +"adding\n" +"fields or variants is often a better option.\n" +"`#[non_exhaustive]` may be appropriate in scenarios where you're modeling an " +"external\n" +"resource that may change out-of-sync with your library, but is not a general " +"purpose\n" +"tool." +msgstr "" + +#: src\idioms/priv-extend.md:104 +msgid "### Disadvantages" +msgstr "" + +#: src\idioms/priv-extend.md:106 +msgid "" +"`#[non_exhaustive]` can make your code much less ergonomic to use, " +"especially when\n" +"forced to handle unknown enum variants.\n" +"It should only be used when these sorts of evolutions are required " +"**without**\n" +"incrementing the major version." +msgstr "" + +#: src\idioms/priv-extend.md:111 +msgid "" +"When `#[non_exhaustive]` is applied to `enum`s, it forces clients to handle " +"a\n" +"wildcard variant.\n" +"If there is no sensible action to take in this case, this may lead to " +"awkward\n" +"code and code paths that are only executed in extremely rare circumstances.\n" +"If a client decides to `panic!()` in this scenario, it may have been better " +"to\n" +"expose this error at compile time.\n" +"In fact, `#[non_exhaustive]` forces clients to handle the \"Something else\" " +"case;\n" +"there is rarely a sensible action to take in this scenario." +msgstr "" + +#: src\idioms/priv-extend.md:122 +msgid "" +"- [RFC introducing #[non_exhaustive] attribute for enums and structs]" +"(https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" +msgstr "" + +#: src\idioms/rustdoc-init.md:1 +msgid "# Easy doc initialization\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:5 +msgid "" +"If a struct takes significant effort to initialize when writing docs, it can " +"be\r\n" +"quicker to wrap your example with a helper function which takes the struct " +"as an\r\n" +"argument." +msgstr "" + +#: src\idioms/rustdoc-init.md:9 +msgid "## Motivation\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:11 +msgid "" +"Sometimes there is a struct with multiple or complicated parameters and " +"several\r\n" +"methods. Each of these methods should have examples." +msgstr "" + +#: src\idioms/rustdoc-init.md:14 +msgid "For example:" +msgstr "" + +#: src\idioms/rustdoc-init.md:16 +msgid "" +"````rust,ignore\r\n" +"struct Connection {\r\n" +" name: String,\r\n" +" stream: TcpStream,\r\n" +"}\r\n" +"\r\n" +"impl Connection {\r\n" +" /// Sends a request over the connection.\r\n" +" ///\r\n" +" /// # Example\r\n" +" /// ```no_run\r\n" +" /// # // Boilerplate are required to get an example working.\r\n" +" /// # let stream = TcpStream::connect(\"127.0.0.1:34254\");\r\n" +" /// # let connection = Connection { name: \"foo\".to_owned(), stream };" +"\r\n" +" /// # let request = Request::new(\"RequestId\", RequestType::Get, " +"\"payload\");\r\n" +" /// let response = connection.send_request(request);\r\n" +" /// assert!(response.is_ok());\r\n" +" /// ```\r\n" +" fn send_request(&self, request: Request) -> Result {\r\n" +" // ...\r\n" +" }\r\n" +"\r\n" +" /// Oh no, all that boilerplate needs to be repeated here!\r\n" +" fn check_status(&self) -> Status {\r\n" +" // ...\r\n" +" }\r\n" +"}\r\n" +"````" +msgstr "" + +#: src\idioms/rustdoc-init.md:45 +msgid "## Example\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:47 +msgid "" +"Instead of typing all of this boilerplate to create a `Connection` and\r\n" +"`Request`, it is easier to just create a wrapping helper function which " +"takes\r\n" +"them as arguments:" +msgstr "" + +#: src\idioms/rustdoc-init.md:51 +msgid "" +"````rust,ignore\r\n" +"struct Connection {\r\n" +" name: String,\r\n" +" stream: TcpStream,\r\n" +"}\r\n" +"\r\n" +"impl Connection {\r\n" +" /// Sends a request over the connection.\r\n" +" ///\r\n" +" /// # Example\r\n" +" /// ```\r\n" +" /// # fn call_send(connection: Connection, request: Request) {\r\n" +" /// let response = connection.send_request(request);\r\n" +" /// assert!(response.is_ok());\r\n" +" /// # }\r\n" +" /// ```\r\n" +" fn send_request(&self, request: Request) {\r\n" +" // ...\r\n" +" }\r\n" +"}\r\n" +"````" +msgstr "" + +#: src\idioms/rustdoc-init.md:73 +msgid "" +"**Note** in the above example the line `assert!(response.is_ok());` will " +"not\r\n" +"actually run while testing because it is inside a function which is never\r\n" +"invoked." +msgstr "" + +#: src\idioms/rustdoc-init.md:77 +msgid "## Advantages\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:79 +msgid "This is much more concise and avoids repetitive code in examples." +msgstr "" + +#: src\idioms/rustdoc-init.md:81 +msgid "## Disadvantages\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:83 +msgid "" +"As example is in a function, the code will not be tested. Though it will " +"still be\r\n" +"checked to make sure it compiles when running a `cargo test`. So this " +"pattern is\r\n" +"most useful when you need `no_run`. With this, you do not need to add " +"`no_run`." +msgstr "" + +#: src\idioms/rustdoc-init.md:87 +msgid "## Discussion\r" +msgstr "" + +#: src\idioms/rustdoc-init.md:89 +msgid "If assertions are not required this pattern works well." +msgstr "" + +#: src\idioms/rustdoc-init.md:91 +msgid "" +"If they are, an alternative can be to create a public method to create a " +"helper\r\n" +"instance which is annotated with `#[doc(hidden)]` (so that users won't see " +"it).\r\n" +"Then this method can be called inside of rustdoc because it is part of " +"the\r\n" +"crate's public API." +msgstr "" + +#: src\idioms/temporary-mutability.md:1 +msgid "# Temporary mutability" +msgstr "" + +#: src\idioms/temporary-mutability.md:5 +msgid "" +"Often it is necessary to prepare and process some data, but after that data " +"are\n" +"only inspected and never modified. The intention can be made explicit by " +"redefining\n" +"the mutable variable as immutable." +msgstr "" + +#: src\idioms/temporary-mutability.md:9 +msgid "" +"It can be done either by processing data within a nested block or by " +"redefining\n" +"the variable." +msgstr "" + +#: src\idioms/temporary-mutability.md:14 +msgid "Say, vector must be sorted before usage." +msgstr "" + +#: src\idioms/temporary-mutability.md:16 +msgid "Using nested block:" +msgstr "" + +#: src\idioms/temporary-mutability.md:18 +msgid "" +"```rust,ignore\n" +"let data = {\n" +" let mut data = get_vec();\n" +" data.sort();\n" +" data\n" +"};\n" +"\n" +"// Here `data` is immutable.\n" +"```" +msgstr "" + +#: src\idioms/temporary-mutability.md:28 +msgid "Using variable rebinding:" +msgstr "" + +#: src\idioms/temporary-mutability.md:30 +msgid "" +"```rust,ignore\n" +"let mut data = get_vec();\n" +"data.sort();\n" +"let data = data;\n" +"\n" +"// Here `data` is immutable.\n" +"```" +msgstr "" + +#: src\idioms/temporary-mutability.md:40 +msgid "" +"Compiler ensures that you don't accidentally mutate data after some point." +msgstr "" + +#: src\idioms/temporary-mutability.md:44 +msgid "" +"Nested block requires additional indentation of block body.\n" +"One more line to return data from block or redefine variable." +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:1 +msgid "# Return consumed argument on error" +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:5 +msgid "" +"If a fallible function consumes (moves) an argument, return that argument " +"back inside\n" +"an error." +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:10 +msgid "" +"```rust\n" +"pub fn send(value: String) -> Result<(), SendError> {\n" +" println!(\"using {value} in a meaningful way\");\n" +" // Simulate non-deterministic fallible action.\n" +" use std::time::SystemTime;\n" +" let period = " +"SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();\n" +" if period.subsec_nanos() % 2 == 1 {\n" +" Ok(())\n" +" } else {\n" +" Err(SendError(value))\n" +" }\n" +"}\n" +"\n" +"pub struct SendError(String);\n" +"\n" +"fn main() {\n" +" let mut value = \"imagine this is very long string\".to_string();\n" +"\n" +" let success = 's: {\n" +" // Try to send value two times.\n" +" for _ in 0..2 {\n" +" value = match send(value) {\n" +" Ok(()) => break 's true,\n" +" Err(SendError(value)) => value,\n" +" }\n" +" }\n" +" false\n" +" };\n" +"\n" +" println!(\"success: {}\", success);\n" +"}\n" +"```" +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:45 +msgid "" +"In case of error you may want to try some alternative way or to\n" +"retry action in case of non-deterministic function. But if the argument\n" +"is always consumed, you are forced to clone it on every call, which\n" +"is not very efficient." +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:50 +msgid "" +"The standard library uses this approach in e.g. `String::from_utf8` method.\n" +"When given a vector that doesn't contain valid UTF-8, a `FromUtf8Error`\n" +"is returned.\n" +"You can get original vector back using `FromUtf8Error::into_bytes` method." +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:57 +msgid "Better performance because of moving arguments whenever possible." +msgstr "" + +#: src\idioms/return-consumed-arg-on-error.md:61 +msgid "Slightly more complex error types." +msgstr "" + +#: src\patterns/index.md:1 +msgid "# Design Patterns" +msgstr "" + +#: src\patterns/index.md:3 +msgid "" +"[Design patterns](https://en.wikipedia.org/wiki/Software_design_pattern) " +"are\n" +"\"general reusable solutions to a commonly occurring problem within a given\n" +"context in software design\". Design patterns are a great way to describe " +"the\n" +"culture of a programming language. Design patterns are very language-" +"specific -\n" +"what is a pattern in one language may be unnecessary in another due to a\n" +"language feature, or impossible to express due to a missing feature." +msgstr "" + +#: src\patterns/index.md:10 +msgid "" +"If overused, design patterns can add unnecessary complexity to programs.\n" +"However, they are a great way to share intermediate and advanced level " +"knowledge\n" +"about a programming language." +msgstr "" + +#: src\patterns/index.md:16 +msgid "" +"Rust has many unique features. These features give us great benefit by " +"removing\n" +"whole classes of problems. Some of them are also patterns that are _unique_ " +"to Rust." +msgstr "" + +#: src\patterns/index.md:19 +msgid "## YAGNI" +msgstr "" + +#: src\patterns/index.md:21 +msgid "" +"YAGNI is an acronym that stands for `You Aren't Going to Need It`.\n" +"It's a vital software design principle to apply as you write code." +msgstr "" + +#: src\patterns/index.md:24 +msgid "> The best code I ever wrote was code I never wrote." +msgstr "" + +#: src\patterns/index.md:26 +msgid "" +"If we apply YAGNI to design patterns, we see that the features of Rust allow " +"us to\n" +"throw out many patterns. For instance, there is no need for the [strategy " +"pattern](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"in Rust because we can just use [traits](https://doc.rust-lang.org/book/" +"traits.html)." +msgstr "" + +#: src\patterns/behavioural/intro.md:1 +msgid "# Behavioural Patterns" +msgstr "" + +#: src\patterns/behavioural/intro.md:3 +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" +msgstr "" + +#: src\patterns/behavioural/intro.md:5 +msgid "" +"> Design patterns that identify common communication patterns among " +"objects.\n" +"> By doing so, these patterns increase flexibility in carrying out " +"communication." +msgstr "" + +#: src\patterns/behavioural/command.md:1 +msgid "# Command" +msgstr "" + +#: src\patterns/behavioural/command.md:5 +msgid "" +"The basic idea of the Command pattern is to separate out actions into its " +"own\n" +"objects and pass them as parameters." +msgstr "" + +#: src\patterns/behavioural/command.md:10 +msgid "" +"Suppose we have a sequence of actions or transactions encapsulated as " +"objects.\n" +"We want these actions or commands to be executed or invoked in some order " +"later\n" +"at different time. These commands may also be triggered as a result of some " +"event.\n" +"For example, when a user pushes a button, or on arrival of a data packet.\n" +"In addition, these commands might be undoable. This may come in useful for\n" +"operations of an editor. We might want to store logs of executed commands so " +"that\n" +"we could reapply the changes later if the system crashes." +msgstr "" + +#: src\patterns/behavioural/command.md:20 +msgid "" +"Define two database operations `create table` and `add field`. Each of " +"these\n" +"operations is a command which knows how to undo the command, e.g., `drop " +"table`\n" +"and `remove field`. When a user invokes a database migration operation then " +"each\n" +"command is executed in the defined order, and when the user invokes the " +"rollback\n" +"operation then the whole set of commands is invoked in reverse order." +msgstr "" + +#: src\patterns/behavioural/command.md:26 +msgid "## Approach: Using trait objects" +msgstr "" + +#: src\patterns/behavioural/command.md:28 +msgid "" +"We define a common trait which encapsulates our command with two operations\n" +"`execute` and `rollback`. All command `structs` must implement this trait." +msgstr "" + +#: src\patterns/behavioural/command.md:31 +msgid "" +"```rust\n" +"pub trait Migration {\n" +" fn execute(&self) -> &str;\n" +" fn rollback(&self) -> &str;\n" +"}\n" +"\n" +"pub struct CreateTable;\n" +"impl Migration for CreateTable {\n" +" fn execute(&self) -> &str {\n" +" \"create table\"\n" +" }\n" +" fn rollback(&self) -> &str {\n" +" \"drop table\"\n" +" }\n" +"}\n" +"\n" +"pub struct AddField;\n" +"impl Migration for AddField {\n" +" fn execute(&self) -> &str {\n" +" \"add field\"\n" +" }\n" +" fn rollback(&self) -> &str {\n" +" \"remove field\"\n" +" }\n" +"}\n" +"\n" +"struct Schema {\n" +" commands: Vec>,\n" +"}\n" +"\n" +"impl Schema {\n" +" fn new() -> Self {\n" +" Self { commands: vec![] }\n" +" }\n" +"\n" +" fn add_migration(&mut self, cmd: Box) {\n" +" self.commands.push(cmd);\n" +" }\n" +"\n" +" fn execute(&self) -> Vec<&str> {\n" +" self.commands.iter().map(|cmd| cmd.execute()).collect()\n" +" }\n" +" fn rollback(&self) -> Vec<&str> {\n" +" self.commands\n" +" .iter()\n" +" .rev() // reverse iterator's direction\n" +" .map(|cmd| cmd.rollback())\n" +" .collect()\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let mut schema = Schema::new();\n" +"\n" +" let cmd = Box::new(CreateTable);\n" +" schema.add_migration(cmd);\n" +" let cmd = Box::new(AddField);\n" +" schema.add_migration(cmd);\n" +"\n" +" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" +" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/command.md:95 +msgid "## Approach: Using function pointers" +msgstr "" + +#: src\patterns/behavioural/command.md:97 +msgid "" +"We could follow another approach by creating each individual command as\n" +"a different function and store function pointers to invoke these functions " +"later\n" +"at a different time. Since function pointers implement all three traits " +"`Fn`,\n" +"`FnMut`, and `FnOnce` we could as well pass and store closures instead of\n" +"function pointers." +msgstr "" + +#: src\patterns/behavioural/command.md:103 +msgid "" +"```rust\n" +"type FnPtr = fn() -> String;\n" +"struct Command {\n" +" execute: FnPtr,\n" +" rollback: FnPtr,\n" +"}\n" +"\n" +"struct Schema {\n" +" commands: Vec,\n" +"}\n" +"\n" +"impl Schema {\n" +" fn new() -> Self {\n" +" Self { commands: vec![] }\n" +" }\n" +" fn add_migration(&mut self, execute: FnPtr, rollback: FnPtr) {\n" +" self.commands.push(Command { execute, rollback });\n" +" }\n" +" fn execute(&self) -> Vec {\n" +" self.commands.iter().map(|cmd| (cmd.execute)()).collect()\n" +" }\n" +" fn rollback(&self) -> Vec {\n" +" self.commands\n" +" .iter()\n" +" .rev()\n" +" .map(|cmd| (cmd.rollback)())\n" +" .collect()\n" +" }\n" +"}\n" +"\n" +"fn add_field() -> String {\n" +" \"add field\".to_string()\n" +"}\n" +"\n" +"fn remove_field() -> String {\n" +" \"remove field\".to_string()\n" +"}\n" +"\n" +"fn main() {\n" +" let mut schema = Schema::new();\n" +" schema.add_migration(|| \"create table\".to_string(), || \"drop " +"table\".to_string());\n" +" schema.add_migration(add_field, remove_field);\n" +" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" +" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/command.md:150 +msgid "## Approach: Using `Fn` trait objects" +msgstr "" + +#: src\patterns/behavioural/command.md:152 +msgid "" +"Finally, instead of defining a common command trait we could store\n" +"each command implementing the `Fn` trait separately in vectors." +msgstr "" + +#: src\patterns/behavioural/command.md:155 +msgid "" +"```rust\n" +"type Migration<'a> = Box &'a str>;\n" +"\n" +"struct Schema<'a> {\n" +" executes: Vec>,\n" +" rollbacks: Vec>,\n" +"}\n" +"\n" +"impl<'a> Schema<'a> {\n" +" fn new() -> Self {\n" +" Self {\n" +" executes: vec![],\n" +" rollbacks: vec![],\n" +" }\n" +" }\n" +" fn add_migration(&mut self, execute: E, rollback: R)\n" +" where\n" +" E: Fn() -> &'a str + 'static,\n" +" R: Fn() -> &'a str + 'static,\n" +" {\n" +" self.executes.push(Box::new(execute));\n" +" self.rollbacks.push(Box::new(rollback));\n" +" }\n" +" fn execute(&self) -> Vec<&str> {\n" +" self.executes.iter().map(|cmd| cmd()).collect()\n" +" }\n" +" fn rollback(&self) -> Vec<&str> {\n" +" self.rollbacks.iter().rev().map(|cmd| cmd()).collect()\n" +" }\n" +"}\n" +"\n" +"fn add_field() -> &'static str {\n" +" \"add field\"\n" +"}\n" +"\n" +"fn remove_field() -> &'static str {\n" +" \"remove field\"\n" +"}\n" +"\n" +"fn main() {\n" +" let mut schema = Schema::new();\n" +" schema.add_migration(|| \"create table\", || \"drop table\");\n" +" schema.add_migration(add_field, remove_field);\n" +" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" +" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/command.md:205 +msgid "" +"If our commands are small and may be defined as functions or passed as a " +"closure\n" +"then using function pointers might be preferable since it does not exploit\n" +"dynamic dispatch. But if our command is a whole struct with a bunch of " +"functions\n" +"and variables defined as seperated module then using trait objects would be\n" +"more suitable. A case of application can be found in [`actix`](https://" +"actix.rs/),\n" +"which uses trait objects when it registers a handler function for routes.\n" +"In case of using `Fn` trait objects we can create and use commands in the " +"same\n" +"way as we used in case of function pointers." +msgstr "" + +#: src\patterns/behavioural/command.md:214 +msgid "" +"As performance, there is always a trade-off between performance and code\n" +"simplicity and organisation. Static dispatch gives faster performance, " +"while\n" +"dynamic dispatch provides flexibility when we structure our application." +msgstr "" + +#: src\patterns/behavioural/command.md:220 +msgid "" +"- [Command pattern](https://en.wikipedia.org/wiki/Command_pattern)\n" +"\n" +"- [Another example for the `command` pattern](https://web.archive.org/web/" +"20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:1 +msgid "# Interpreter" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:5 +msgid "" +"If a problem occurs very often and requires long and repetitive steps to " +"solve\n" +"it, then the problem instances might be expressed in a simple language and " +"an\n" +"interpreter object could solve it by interpreting the sentences written in " +"this\n" +"simple language." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:10 +msgid "Basically, for any kind of problems we define:" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:12 +msgid "" +"- A [domain specific language](https://en.wikipedia.org/wiki/Domain-" +"specific_language),\n" +"- A grammar for this language,\n" +"- An interpreter that solves the problem instances." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:18 +msgid "" +"Our goal is to translate simple mathematical expressions into postfix " +"expressions\n" +"(or [Reverse Polish notation](https://en.wikipedia.org/wiki/" +"Reverse_Polish_notation))\n" +"For simplicity, our expressions consist of ten digits `0`, ..., `9` and two\n" +"operations `+`, `-`. For example, the expression `2 + 4` is translated into\n" +"`2 4 +`." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:24 +msgid "## Context Free Grammar for our problem" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:26 +msgid "" +"Our task is translating infix expressions into postfix ones. Let's define a " +"context\n" +"free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-" +"`,\n" +"where:" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:30 +msgid "" +"- Terminal symbols: `0`, `...`, `9`, `+`, `-`\n" +"- Non-terminal symbols: `exp`, `term`\n" +"- Start symbol is `exp`\n" +"- And the following are production rules" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:35 +msgid "" +"```ignore\n" +"exp -> exp + term\n" +"exp -> exp - term\n" +"exp -> term\n" +"term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n" +"```" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:42 +msgid "" +"**NOTE:** This grammar should be further transformed depending on what we " +"are going\n" +"to do with it. For example, we might need to remove left recursion. For " +"more\n" +"details please see [Compilers: Principles,Techniques, and Tools](https://" +"en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)\n" +"(aka Dragon Book)." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:47 +msgid "## Solution" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:49 +msgid "" +"We simply implement a recursive descent parser. For simplicity's sake, the " +"code\n" +"panics when an expression is syntactically wrong (for example `2-34` or `2+5-" +"`\n" +"are wrong according to the grammar definition)." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:53 +msgid "" +"```rust\n" +"pub struct Interpreter<'a> {\n" +" it: std::str::Chars<'a>,\n" +"}\n" +"\n" +"impl<'a> Interpreter<'a> {\n" +"\n" +" pub fn new(infix: &'a str) -> Self {\n" +" Self { it: infix.chars() }\n" +" }\n" +"\n" +" fn next_char(&mut self) -> Option {\n" +" self.it.next()\n" +" }\n" +"\n" +" pub fn interpret(&mut self, out: &mut String) {\n" +" self.term(out);\n" +"\n" +" while let Some(op) = self.next_char() {\n" +" if op == '+' || op == '-' {\n" +" self.term(out);\n" +" out.push(op);\n" +" } else {\n" +" panic!(\"Unexpected symbol '{}'\", op);\n" +" }\n" +" }\n" +" }\n" +"\n" +" fn term(&mut self, out: &mut String) {\n" +" match self.next_char() {\n" +" Some(ch) if ch.is_digit(10) => out.push(ch),\n" +" Some(ch) => panic!(\"Unexpected symbol '{}'\", ch),\n" +" None => panic!(\"Unexpected end of string\"),\n" +" }\n" +" }\n" +"}\n" +"\n" +"pub fn main() {\n" +" let mut intr = Interpreter::new(\"2+3\");\n" +" let mut postfix = String::new();\n" +" intr.interpret(&mut postfix);\n" +" assert_eq!(postfix, \"23+\");\n" +"\n" +" intr = Interpreter::new(\"1-2+3-4\");\n" +" postfix.clear();\n" +" intr.interpret(&mut postfix);\n" +" assert_eq!(postfix, \"12-3+4-\");\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:105 +msgid "" +"There may be a wrong perception that the Interpreter design pattern is about " +"design\n" +"grammars for formal languages and implementation of parsers for these " +"grammars.\n" +"In fact, this pattern is about expressing problem instances in a more " +"specific\n" +"way and implementing functions/classes/structs that solve these problem " +"instances.\n" +"Rust language has `macro_rules!` that allow us to define special syntax and " +"rules\n" +"on how to expand this syntax into source code." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:112 +msgid "" +"In the following example we create a simple `macro_rules!` that computes\n" +"[Euclidean length](https://en.wikipedia.org/wiki/Euclidean_distance) of `n`\n" +"dimensional vectors. Writing `norm!(x,1,2)` might be easier to express and " +"more\n" +"efficient than packing `x,1,2` into a `Vec` and calling a function " +"computing\n" +"the length." +msgstr "" + +#: src\patterns/behavioural/interpreter.md:118 +msgid "" +"```rust\n" +"macro_rules! norm {\n" +" ($($element:expr),*) => {\n" +" {\n" +" let mut n = 0.0;\n" +" $(\n" +" n += ($element as f64)*($element as f64);\n" +" )*\n" +" n.sqrt()\n" +" }\n" +" };\n" +"}\n" +"\n" +"fn main() {\n" +" let x = -3f64;\n" +" let y = 4f64;\n" +"\n" +" assert_eq!(3f64, norm!(x));\n" +" assert_eq!(5f64, norm!(x, y));\n" +" assert_eq!(0f64, norm!(0, 0, 0)); \n" +" assert_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5));\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/interpreter.md:144 +msgid "" +"- [Interpreter pattern](https://en.wikipedia.org/wiki/Interpreter_pattern)\n" +"- [Context free grammar](https://en.wikipedia.org/wiki/Context-" +"free_grammar)\n" +"- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" +msgstr "" + +#: src\patterns/behavioural/newtype.md:1 +msgid "# Newtype" +msgstr "" + +#: src\patterns/behavioural/newtype.md:3 +msgid "" +"What if in some cases we want a type to behave similar to another type or\n" +"enforce some behaviour at compile time when using only type aliases would\n" +"not be enough?" +msgstr "" + +#: src\patterns/behavioural/newtype.md:7 +msgid "" +"For example, if we want to create a custom `Display` implementation for " +"`String`\n" +"due to security considerations (e.g. passwords)." +msgstr "" + +#: src\patterns/behavioural/newtype.md:10 +msgid "" +"For such cases we could use the `Newtype` pattern to provide **type " +"safety**\n" +"and **encapsulation**." +msgstr "" + +#: src\patterns/behavioural/newtype.md:15 +msgid "" +"Use a tuple struct with a single field to make an opaque wrapper for a " +"type.\n" +"This creates a new type, rather than an alias to a type (`type` items)." +msgstr "" + +#: src\patterns/behavioural/newtype.md:20 +msgid "" +"```rust,ignore\n" +"// Some type, not necessarily in the same module or even crate.\n" +"struct Foo {\n" +" //..\n" +"}\n" +"\n" +"impl Foo {\n" +" // These functions are not present on Bar.\n" +" //..\n" +"}\n" +"\n" +"// The newtype.\n" +"pub struct Bar(Foo);\n" +"\n" +"impl Bar {\n" +" // Constructor.\n" +" pub fn new(\n" +" //..\n" +" ) -> Self {\n" +"\n" +" //..\n" +"\n" +" }\n" +"\n" +" //..\n" +"}\n" +"\n" +"fn main() {\n" +" let b = Bar::new(...);\n" +"\n" +" // Foo and Bar are type incompatible, the following do not type check.\n" +" // let f: Foo = b;\n" +" // let b: Bar = Foo { ... };\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/newtype.md:58 +msgid "" +"The primary motivation for newtypes is abstraction. It allows you to share\n" +"implementation details between types while precisely controlling the " +"interface.\n" +"By using a newtype rather than exposing the implementation type as part of " +"an\n" +"API, it allows you to change implementation backwards compatibly." +msgstr "" + +#: src\patterns/behavioural/newtype.md:63 +msgid "" +"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give\n" +"distinguishable `Miles` and `Kilometres`." +msgstr "" + +#: src\patterns/behavioural/newtype.md:68 +msgid "" +"The wrapped and wrapper types are not type compatible (as opposed to using\n" +"`type`), so users of the newtype will never 'confuse' the wrapped and " +"wrapper\n" +"types." +msgstr "" + +#: src\patterns/behavioural/newtype.md:72 +msgid "Newtypes are a zero-cost abstraction - there is no runtime overhead." +msgstr "" + +#: src\patterns/behavioural/newtype.md:74 +msgid "" +"The privacy system ensures that users cannot access the wrapped type (if " +"the\n" +"field is private, which it is by default)." +msgstr "" + +#: src\patterns/behavioural/newtype.md:79 +msgid "" +"The downside of newtypes (especially compared with type aliases), is that " +"there\n" +"is no special language support. This means there can be _a lot_ of " +"boilerplate.\n" +"You need a 'pass through' method for every method you want to expose on the\n" +"wrapped type, and an impl for every trait you want to also be implemented " +"for\n" +"the wrapper type." +msgstr "" + +#: src\patterns/behavioural/newtype.md:87 +msgid "" +"Newtypes are very common in Rust code. Abstraction or representing units are " +"the\n" +"most common uses, but they can be used for other reasons:" +msgstr "" + +#: src\patterns/behavioural/newtype.md:90 +msgid "" +"- restricting functionality (reduce the functions exposed or traits " +"implemented),\n" +"- making a type with copy semantics have move semantics,\n" +"- abstraction by providing a more concrete type and thus hiding internal " +"types,\n" +" e.g.," +msgstr "" + +#: src\patterns/behavioural/newtype.md:95 +msgid "" +"```rust,ignore\n" +"pub struct Foo(Bar);\n" +"```" +msgstr "" + +#: src\patterns/behavioural/newtype.md:99 +msgid "" +"Here, `Bar` might be some public, generic type and `T1` and `T2` are some " +"internal\n" +"types. Users of our module shouldn't know that we implement `Foo` by using a " +"`Bar`,\n" +"but what we're really hiding here is the types `T1` and `T2`, and how they " +"are used\n" +"with `Bar`." +msgstr "" + +#: src\patterns/behavioural/newtype.md:106 +msgid "" +"- [Advanced Types in the book](https://doc.rust-lang.org/book/ch19-04-" +"advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-" +"safety-and-abstraction)\n" +"- [Newtypes in Haskell](https://wiki.haskell.org/Newtype)\n" +"- [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-" +"types.html#creating-type-synonyms-with-type-aliases)\n" +"- [derive_more](https://crates.io/crates/derive_more), a crate for deriving " +"many\n" +" builtin traits on newtypes.\n" +"- [The Newtype Pattern In Rust](https://www.worthe-it.co.za/blog/2020-10-31-" +"newtype-pattern-in-rust.html)" +msgstr "" + +#: src\patterns/behavioural/RAII.md:1 +msgid "# RAII with guards" +msgstr "" + +#: src\patterns/behavioural/RAII.md:5 +msgid "" +"[RAII][wikipedia] stands for \"Resource Acquisition is Initialisation\" " +"which is a\n" +"terrible name. The essence of the pattern is that resource initialisation is " +"done\n" +"in the constructor of an object and finalisation in the destructor. This " +"pattern\n" +"is extended in Rust by using a RAII object as a guard of some resource and " +"relying\n" +"on the type system to ensure that access is always mediated by the guard " +"object." +msgstr "" + +#: src\patterns/behavioural/RAII.md:13 +msgid "" +"Mutex guards are the classic example of this pattern from the std library " +"(this\n" +"is a simplified version of the real implementation):" +msgstr "" + +#: src\patterns/behavioural/RAII.md:16 +msgid "" +"```rust,ignore\n" +"use std::ops::Deref;\n" +"\n" +"struct Foo {}\n" +"\n" +"struct Mutex {\n" +" // We keep a reference to our data: T here.\n" +" //..\n" +"}\n" +"\n" +"struct MutexGuard<'a, T: 'a> {\n" +" data: &'a T,\n" +" //..\n" +"}\n" +"\n" +"// Locking the mutex is explicit.\n" +"impl Mutex {\n" +" fn lock(&self) -> MutexGuard {\n" +" // Lock the underlying OS mutex.\n" +" //..\n" +"\n" +" // MutexGuard keeps a reference to self\n" +" MutexGuard {\n" +" data: self,\n" +" //..\n" +" }\n" +" }\n" +"}\n" +"\n" +"// Destructor for unlocking the mutex.\n" +"impl<'a, T> Drop for MutexGuard<'a, T> {\n" +" fn drop(&mut self) {\n" +" // Unlock the underlying OS mutex.\n" +" //..\n" +" }\n" +"}\n" +"\n" +"// Implementing Deref means we can treat MutexGuard like a pointer to T.\n" +"impl<'a, T> Deref for MutexGuard<'a, T> {\n" +" type Target = T;\n" +"\n" +" fn deref(&self) -> &T {\n" +" self.data\n" +" }\n" +"}\n" +"\n" +"fn baz(x: Mutex) {\n" +" let xx = x.lock();\n" +" xx.foo(); // foo is a method on Foo.\n" +" // The borrow checker ensures we can't store a reference to the " +"underlying\n" +" // Foo which will outlive the guard xx.\n" +"\n" +" // x is unlocked when we exit this function and xx's destructor is " +"executed.\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/RAII.md:74 +msgid "" +"Where a resource must be finalised after use, RAII can be used to do this\n" +"finalisation. If it is an error to access that resource after finalisation, " +"then\n" +"this pattern can be used to prevent such errors." +msgstr "" + +#: src\patterns/behavioural/RAII.md:80 +msgid "" +"Prevents errors where a resource is not finalised and where a resource is " +"used\n" +"after finalisation." +msgstr "" + +#: src\patterns/behavioural/RAII.md:85 +msgid "" +"RAII is a useful pattern for ensuring resources are properly deallocated or\n" +"finalised. We can make use of the borrow checker in Rust to statically " +"prevent\n" +"errors stemming from using resources after finalisation takes place." +msgstr "" + +#: src\patterns/behavioural/RAII.md:89 +msgid "" +"The core aim of the borrow checker is to ensure that references to data do " +"not\n" +"outlive that data. The RAII guard pattern works because the guard object\n" +"contains a reference to the underlying resource and only exposes such\n" +"references. Rust ensures that the guard cannot outlive the underlying " +"resource\n" +"and that references to the resource mediated by the guard cannot outlive " +"the\n" +"guard. To see how this works it is helpful to examine the signature of " +"`deref`\n" +"without lifetime elision:" +msgstr "" + +#: src\patterns/behavioural/RAII.md:97 +msgid "" +"```rust,ignore\n" +"fn deref<'a>(&'a self) -> &'a T {\n" +" //..\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/RAII.md:103 +msgid "" +"The returned reference to the resource has the same lifetime as `self` " +"(`'a`).\n" +"The borrow checker therefore ensures that the lifetime of the reference to " +"`T`\n" +"is shorter than the lifetime of `self`." +msgstr "" + +#: src\patterns/behavioural/RAII.md:107 +msgid "" +"Note that implementing `Deref` is not a core part of this pattern, it only " +"makes\n" +"using the guard object more ergonomic. Implementing a `get` method on the " +"guard\n" +"works just as well." +msgstr "" + +#: src\patterns/behavioural/RAII.md:113 +msgid "[Finalisation in destructors idiom](../../idioms/dtor-finally.md)" +msgstr "" + +#: src\patterns/behavioural/RAII.md:115 +msgid "" +"RAII is a common pattern in C++: [cppreference.com](http://" +"en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." +msgstr "" + +#: src\patterns/behavioural/RAII.md:120 +msgid "" +"[Style guide entry](https://doc.rust-lang.org/1.0.0/style/ownership/" +"raii.html)\n" +"(currently just a placeholder)." +msgstr "" + +#: src\patterns/behavioural/strategy.md:1 +msgid "# Strategy (aka Policy)" +msgstr "" + +#: src\patterns/behavioural/strategy.md:5 +msgid "" +"The [Strategy design pattern](https://en.wikipedia.org/wiki/" +"Strategy_pattern)\n" +"is a technique that enables separation of concerns.\n" +"It also allows to decouple software modules through [Dependency Inversion]" +"(https://en.wikipedia.org/wiki/Dependency_inversion_principle)." +msgstr "" + +#: src\patterns/behavioural/strategy.md:9 +msgid "" +"The basic idea behind the Strategy pattern is that, given an algorithm " +"solving\n" +"a particular problem, we define only the skeleton of the algorithm at an " +"abstract\n" +"level, and we separate the specific algorithm’s implementation into " +"different parts." +msgstr "" + +#: src\patterns/behavioural/strategy.md:13 +msgid "" +"In this way, a client using the algorithm may choose a specific " +"implementation,\n" +"while the general algorithm workflow remains the same. In other words, the " +"abstract\n" +"specification of the class does not depend on the specific implementation of " +"the\n" +"derived class, but specific implementation must adhere to the abstract " +"specification.\n" +"This is why we call it \"Dependency Inversion\"." +msgstr "" + +#: src\patterns/behavioural/strategy.md:21 +msgid "" +"Imagine we are working on a project that generates reports every month.\n" +"We need the reports to be generated in different formats (strategies), " +"e.g.,\n" +"in `JSON` or `Plain Text` formats.\n" +"But things vary over time, and we don't know what kind of requirement we may " +"get\n" +"in the future. For example, we may need to generate our report in a " +"completely new\n" +"format, or just modify one of the existing formats." +msgstr "" + +#: src\patterns/behavioural/strategy.md:30 +msgid "" +"In this example our invariants (or abstractions) are `Context`, " +"`Formatter`,\n" +"and `Report`, while `Text` and `Json` are our strategy structs. These " +"strategies\n" +"have to implement the `Formatter` trait." +msgstr "" + +#: src\patterns/behavioural/strategy.md:34 +msgid "" +"```rust\n" +"use std::collections::HashMap;\n" +"\n" +"type Data = HashMap;\n" +"\n" +"trait Formatter {\n" +" fn format(&self, data: &Data, buf: &mut String);\n" +"}\n" +"\n" +"struct Report;\n" +"\n" +"impl Report {\n" +" // Write should be used but we kept it as String to ignore error " +"handling\n" +" fn generate(g: T, s: &mut String) {\n" +" // backend operations...\n" +" let mut data = HashMap::new();\n" +" data.insert(\"one\".to_string(), 1);\n" +" data.insert(\"two\".to_string(), 2);\n" +" // generate report\n" +" g.format(&data, s);\n" +" }\n" +"}\n" +"\n" +"struct Text;\n" +"impl Formatter for Text {\n" +" fn format(&self, data: &Data, buf: &mut String) {\n" +" for (k, v) in data {\n" +" let entry = format!(\"{} {}\\n\", k, v);\n" +" buf.push_str(&entry);\n" +" }\n" +" }\n" +"}\n" +"\n" +"struct Json;\n" +"impl Formatter for Json {\n" +" fn format(&self, data: &Data, buf: &mut String) {\n" +" buf.push('[');\n" +" for (k, v) in data.into_iter() {\n" +" let entry = format!(r#\"{{\"{}\":\"{}\"}}\"#, k, v);\n" +" buf.push_str(&entry);\n" +" buf.push(',');\n" +" }\n" +" if !data.is_empty() {\n" +" buf.pop(); // remove extra , at the end\n" +" }\n" +" buf.push(']');\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let mut s = String::from(\"\");\n" +" Report::generate(Text, &mut s);\n" +" assert!(s.contains(\"one 1\"));\n" +" assert!(s.contains(\"two 2\"));\n" +"\n" +" s.clear(); // reuse the same buffer\n" +" Report::generate(Json, &mut s);\n" +" assert!(s.contains(r#\"{\"one\":\"1\"}\"#));\n" +" assert!(s.contains(r#\"{\"two\":\"2\"}\"#));\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/strategy.md:98 +msgid "" +"The main advantage is separation of concerns. For example, in this case " +"`Report`\n" +"does not know anything about specific implementations of `Json` and `Text`,\n" +"whereas the output implementations does not care about how data is " +"preprocessed,\n" +"stored, and fetched. The only thing they have to know is context and a " +"specific\n" +"trait and method to implement, i.e,`Formatter` and `run`." +msgstr "" + +#: src\patterns/behavioural/strategy.md:106 +msgid "" +"For each strategy there must be implemented at least one module, so number " +"of modules\n" +"increases with number of strategies. If there are many strategies to choose " +"from\n" +"then users have to know how strategies differ from one another." +msgstr "" + +#: src\patterns/behavioural/strategy.md:112 +msgid "" +"In the previous example all strategies are implemented in a single file.\n" +"Ways of providing different strategies includes:" +msgstr "" + +#: src\patterns/behavioural/strategy.md:115 +msgid "" +"- All in one file (as shown in this example, similar to being separated as " +"modules)\n" +"- Separated as modules, E.g. `formatter::json` module, `formatter::text` " +"module\n" +"- Use compiler feature flags, E.g. `json` feature, `text` feature\n" +"- Separated as crates, E.g. `json` crate, `text` crate" +msgstr "" + +#: src\patterns/behavioural/strategy.md:120 +msgid "" +"Serde crate is a good example of the `Strategy` pattern in action. Serde " +"allows\n" +"[full customization](https://serde.rs/custom-serialization.html) of the " +"serialization\n" +"behavior by manually implementing `Serialize` and `Deserialize` traits for " +"our\n" +"type. For example, we could easily swap `serde_json` with `serde_cbor` since " +"they\n" +"expose similar methods. Having this makes the helper crate `serde_transcode` " +"much\n" +"more useful and ergonomic." +msgstr "" + +#: src\patterns/behavioural/strategy.md:127 +msgid "" +"However, we don't need to use traits in order to design this pattern in Rust." +msgstr "" + +#: src\patterns/behavioural/strategy.md:129 +msgid "" +"The following toy example demonstrates the idea of the Strategy pattern " +"using Rust\n" +"`closures`:" +msgstr "" + +#: src\patterns/behavioural/strategy.md:132 +msgid "" +"```rust\n" +"struct Adder;\n" +"impl Adder {\n" +" pub fn add(x: u8, y: u8, f: F) -> u8\n" +" where\n" +" F: Fn(u8, u8) -> u8,\n" +" {\n" +" f(x, y)\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let arith_adder = |x, y| x + y;\n" +" let bool_adder = |x, y| {\n" +" if x == 1 || y == 1 {\n" +" 1\n" +" } else {\n" +" 0\n" +" }\n" +" };\n" +" let custom_adder = |x, y| 2 * x + y;\n" +"\n" +" assert_eq!(9, Adder::add(4, 5, arith_adder));\n" +" assert_eq!(0, Adder::add(0, 0, bool_adder));\n" +" assert_eq!(5, Adder::add(1, 3, custom_adder));\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/strategy.md:160 +msgid "In fact, Rust already uses this idea for `Options`'s `map` method:" +msgstr "" + +#: src\patterns/behavioural/strategy.md:162 +msgid "" +"```rust\n" +"fn main() {\n" +" let val = Some(\"Rust\");\n" +"\n" +" let len_strategy = |s: &str| s.len();\n" +" assert_eq!(4, val.map(len_strategy).unwrap());\n" +"\n" +" let first_byte_strategy = |s: &str| s.bytes().next().unwrap();\n" +" assert_eq!(82, val.map(first_byte_strategy).unwrap());\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/strategy.md:176 +msgid "" +"- [Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"- [Dependency Injection](https://en.wikipedia.org/wiki/" +"Dependency_injection)\n" +"- [Policy Based Design](https://en.wikipedia.org/wiki/Modern_C+" +"+_Design#Policy-based_design)" +msgstr "" + +#: src\patterns/behavioural/visitor.md:1 +msgid "# Visitor" +msgstr "" + +#: src\patterns/behavioural/visitor.md:5 +msgid "" +"A visitor encapsulates an algorithm that operates over a heterogeneous\n" +"collection of objects. It allows multiple different algorithms to be " +"written\n" +"over the same data without having to modify the data (or their primary\n" +"behaviour)." +msgstr "" + +#: src\patterns/behavioural/visitor.md:10 +msgid "" +"Furthermore, the visitor pattern allows separating the traversal of\n" +"a collection of objects from the operations performed on each object." +msgstr "" + +#: src\patterns/behavioural/visitor.md:15 +msgid "" +"```rust,ignore\n" +"// The data we will visit\n" +"mod ast {\n" +" pub enum Stmt {\n" +" Expr(Expr),\n" +" Let(Name, Expr),\n" +" }\n" +"\n" +" pub struct Name {\n" +" value: String,\n" +" }\n" +"\n" +" pub enum Expr {\n" +" IntLit(i64),\n" +" Add(Box, Box),\n" +" Sub(Box, Box),\n" +" }\n" +"}\n" +"\n" +"// The abstract visitor\n" +"mod visit {\n" +" use ast::*;\n" +"\n" +" pub trait Visitor {\n" +" fn visit_name(&mut self, n: &Name) -> T;\n" +" fn visit_stmt(&mut self, s: &Stmt) -> T;\n" +" fn visit_expr(&mut self, e: &Expr) -> T;\n" +" }\n" +"}\n" +"\n" +"use visit::*;\n" +"use ast::*;\n" +"\n" +"// An example concrete implementation - walks the AST interpreting it as " +"code.\n" +"struct Interpreter;\n" +"impl Visitor for Interpreter {\n" +" fn visit_name(&mut self, n: &Name) -> i64 { panic!() }\n" +" fn visit_stmt(&mut self, s: &Stmt) -> i64 {\n" +" match *s {\n" +" Stmt::Expr(ref e) => self.visit_expr(e),\n" +" Stmt::Let(..) => unimplemented!(),\n" +" }\n" +" }\n" +"\n" +" fn visit_expr(&mut self, e: &Expr) -> i64 {\n" +" match *e {\n" +" Expr::IntLit(n) => n,\n" +" Expr::Add(ref lhs, ref rhs) => self.visit_expr(lhs) + " +"self.visit_expr(rhs),\n" +" Expr::Sub(ref lhs, ref rhs) => self.visit_expr(lhs) - " +"self.visit_expr(rhs),\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/visitor.md:69 +msgid "" +"One could implement further visitors, for example a type checker, without " +"having\n" +"to modify the AST data." +msgstr "" + +#: src\patterns/behavioural/visitor.md:74 +msgid "" +"The visitor pattern is useful anywhere that you want to apply an algorithm " +"to\n" +"heterogeneous data. If data is homogeneous, you can use an iterator-like " +"pattern.\n" +"Using a visitor object (rather than a functional approach) allows the " +"visitor to\n" +"be stateful and thus communicate information between nodes." +msgstr "" + +#: src\patterns/behavioural/visitor.md:81 +msgid "" +"It is common for the `visit_*` methods to return void (as opposed to in the\n" +"example). In that case it is possible to factor out the traversal code and " +"share\n" +"it between algorithms (and also to provide noop default methods). In Rust, " +"the\n" +"common way to do this is to provide `walk_*` functions for each datum. For\n" +"example," +msgstr "" + +#: src\patterns/behavioural/visitor.md:87 +msgid "" +"```rust,ignore\n" +"pub fn walk_expr(visitor: &mut Visitor, e: &Expr) {\n" +" match *e {\n" +" Expr::IntLit(_) => {},\n" +" Expr::Add(ref lhs, ref rhs) => {\n" +" visitor.visit_expr(lhs);\n" +" visitor.visit_expr(rhs);\n" +" }\n" +" Expr::Sub(ref lhs, ref rhs) => {\n" +" visitor.visit_expr(lhs);\n" +" visitor.visit_expr(rhs);\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/behavioural/visitor.md:103 +msgid "" +"In other languages (e.g., Java) it is common for data to have an `accept` " +"method\n" +"which performs the same duty." +msgstr "" + +#: src\patterns/behavioural/visitor.md:108 +msgid "The visitor pattern is a common pattern in most OO languages." +msgstr "" + +#: src\patterns/behavioural/visitor.md:110 +msgid "[Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern)" +msgstr "" + +#: src\patterns/behavioural/visitor.md:112 +msgid "" +"The [fold](../creational/fold.md) pattern is similar to visitor but " +"produces\n" +"a new version of the visited data structure." +msgstr "" + +#: src\patterns/creational/intro.md:1 +msgid "# Creational Patterns" +msgstr "" + +#: src\patterns/creational/intro.md:3 +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" +msgstr "" + +#: src\patterns/creational/intro.md:5 +msgid "" +"> Design patterns that deal with object creation mechanisms, trying to " +"create objects\n" +"> in a manner suitable to the situation. The basic form of object creation " +"could\n" +"> result in design problems or in added complexity to the design. Creational " +"design\n" +"> patterns solve this problem by somehow controlling this object creation." +msgstr "" + +#: src\patterns/creational/builder.md:1 +msgid "# Builder" +msgstr "" + +#: src\patterns/creational/builder.md:5 +msgid "Construct an object with calls to a builder helper." +msgstr "" + +#: src\patterns/creational/builder.md:9 +msgid "" +"```rust\n" +"#[derive(Debug, PartialEq)]\n" +"pub struct Foo {\n" +" // Lots of complicated fields.\n" +" bar: String,\n" +"}\n" +"\n" +"impl Foo {\n" +" // This method will help users to discover the builder\n" +" pub fn builder() -> FooBuilder {\n" +" FooBuilder::default()\n" +" }\n" +"}\n" +"\n" +"#[derive(Default)]\n" +"pub struct FooBuilder {\n" +" // Probably lots of optional fields.\n" +" bar: String,\n" +"}\n" +"\n" +"impl FooBuilder {\n" +" pub fn new(/* ... */) -> FooBuilder {\n" +" // Set the minimally required fields of Foo.\n" +" FooBuilder {\n" +" bar: String::from(\"X\"),\n" +" }\n" +" }\n" +"\n" +" pub fn name(mut self, bar: String) -> FooBuilder {\n" +" // Set the name on the builder itself, and return the builder by " +"value.\n" +" self.bar = bar;\n" +" self\n" +" }\n" +"\n" +" // If we can get away with not consuming the Builder here, that is an\n" +" // advantage. It means we can use the FooBuilder as a template for " +"constructing\n" +" // many Foos.\n" +" pub fn build(self) -> Foo {\n" +" // Create a Foo from the FooBuilder, applying all settings in " +"FooBuilder\n" +" // to Foo.\n" +" Foo { bar: self.bar }\n" +" }\n" +"}\n" +"\n" +"#[test]\n" +"fn builder_test() {\n" +" let foo = Foo {\n" +" bar: String::from(\"Y\"),\n" +" };\n" +" let foo_from_builder: Foo = " +"FooBuilder::new().name(String::from(\"Y\")).build();\n" +" assert_eq!(foo, foo_from_builder);\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/creational/builder.md:65 +msgid "" +"Useful when you would otherwise require many constructors or where\n" +"construction has side effects." +msgstr "" + +#: src\patterns/creational/builder.md:70 +msgid "Separates methods for building from other methods." +msgstr "" + +#: src\patterns/creational/builder.md:72 +msgid "Prevents proliferation of constructors." +msgstr "" + +#: src\patterns/creational/builder.md:74 +msgid "" +"Can be used for one-liner initialisation as well as more complex " +"construction." +msgstr "" + +#: src\patterns/creational/builder.md:78 +msgid "" +"More complex than creating a struct object directly, or a simple " +"constructor\n" +"function." +msgstr "" + +#: src\patterns/creational/builder.md:83 +msgid "" +"This pattern is seen more frequently in Rust (and for simpler objects) than " +"in\n" +"many other languages because Rust lacks overloading. Since you can only have " +"a\n" +"single method with a given name, having multiple constructors is less nice " +"in\n" +"Rust than in C++, Java, or others." +msgstr "" + +#: src\patterns/creational/builder.md:88 +msgid "" +"This pattern is often used where the builder object is useful in its own " +"right,\n" +"rather than being just a builder. For example, see\n" +"[`std::process::Command`](https://doc.rust-lang.org/std/process/" +"struct.Command.html)\n" +"is a builder for [`Child`](https://doc.rust-lang.org/std/process/" +"struct.Child.html)\n" +"(a process). In these cases, the `T` and `TBuilder` naming pattern is not " +"used." +msgstr "" + +#: src\patterns/creational/builder.md:94 +msgid "" +"The example takes and returns the builder by value. It is often more " +"ergonomic\n" +"(and more efficient) to take and return the builder as a mutable reference. " +"The\n" +"borrow checker makes this work naturally. This approach has the advantage " +"that\n" +"one can write code like" +msgstr "" + +#: src\patterns/creational/builder.md:99 +msgid "" +"```rust,ignore\n" +"let mut fb = FooBuilder::new();\n" +"fb.a();\n" +"fb.b();\n" +"let f = fb.build();\n" +"```" +msgstr "" + +#: src\patterns/creational/builder.md:106 +msgid "as well as the `FooBuilder::new().a().b().build()` style." +msgstr "" + +#: src\patterns/creational/builder.md:110 +msgid "" +"- [Description in the style guide](https://web.archive.org/web/" +"20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/" +"builders.html)\n" +"- [derive_builder](https://crates.io/crates/derive_builder), a crate for " +"automatically\n" +" implementing this pattern while avoiding the boilerplate.\n" +"- [Constructor pattern](../../idioms/ctor.md) for when construction is " +"simpler.\n" +"- [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/" +"Builder_pattern)\n" +"- [Construction of complex values](https://web.archive.org/web/" +"20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-" +"builder)" +msgstr "" + +#: src\patterns/creational/fold.md:1 +msgid "# Fold" +msgstr "" + +#: src\patterns/creational/fold.md:5 +msgid "" +"Run an algorithm over each item in a collection of data to create a new " +"item,\n" +"thus creating a whole new collection." +msgstr "" + +#: src\patterns/creational/fold.md:8 +msgid "" +"The etymology here is unclear to me. The terms 'fold' and 'folder' are used\n" +"in the Rust compiler, although it appears to me to be more like a map than " +"a\n" +"fold in the usual sense. See the discussion below for more details." +msgstr "" + +#: src\patterns/creational/fold.md:14 +msgid "" +"```rust,ignore\n" +"// The data we will fold, a simple AST.\n" +"mod ast {\n" +" pub enum Stmt {\n" +" Expr(Box),\n" +" Let(Box, Box),\n" +" }\n" +"\n" +" pub struct Name {\n" +" value: String,\n" +" }\n" +"\n" +" pub enum Expr {\n" +" IntLit(i64),\n" +" Add(Box, Box),\n" +" Sub(Box, Box),\n" +" }\n" +"}\n" +"\n" +"// The abstract folder\n" +"mod fold {\n" +" use ast::*;\n" +"\n" +" pub trait Folder {\n" +" // A leaf node just returns the node itself. In some cases, we can " +"do this\n" +" // to inner nodes too.\n" +" fn fold_name(&mut self, n: Box) -> Box { n }\n" +" // Create a new inner node by folding its children.\n" +" fn fold_stmt(&mut self, s: Box) -> Box {\n" +" match *s {\n" +" Stmt::Expr(e) => Box::new(Stmt::Expr(self.fold_expr(e))),\n" +" Stmt::Let(n, e) => Box::new(Stmt::Let(self.fold_name(n), " +"self.fold_expr(e))),\n" +" }\n" +" }\n" +" fn fold_expr(&mut self, e: Box) -> Box { ... }\n" +" }\n" +"}\n" +"\n" +"use fold::*;\n" +"use ast::*;\n" +"\n" +"// An example concrete implementation - renames every name to 'foo'.\n" +"struct Renamer;\n" +"impl Folder for Renamer {\n" +" fn fold_name(&mut self, n: Box) -> Box {\n" +" Box::new(Name { value: \"foo\".to_owned() })\n" +" }\n" +" // Use the default methods for the other nodes.\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/creational/fold.md:65 +msgid "" +"The result of running the `Renamer` on an AST is a new AST identical to the " +"old\n" +"one, but with every name changed to `foo`. A real life folder might have " +"some\n" +"state preserved between nodes in the struct itself." +msgstr "" + +#: src\patterns/creational/fold.md:69 +msgid "" +"A folder can also be defined to map one data structure to a different (but\n" +"usually similar) data structure. For example, we could fold an AST into a " +"HIR\n" +"tree (HIR stands for high-level intermediate representation)." +msgstr "" + +#: src\patterns/creational/fold.md:75 +msgid "" +"It is common to want to map a data structure by performing some operation " +"on\n" +"each node in the structure. For simple operations on simple data " +"structures,\n" +"this can be done using `Iterator::map`. For more complex operations, " +"perhaps\n" +"where earlier nodes can affect the operation on later nodes, or where " +"iteration\n" +"over the data structure is non-trivial, using the fold pattern is more\n" +"appropriate." +msgstr "" + +#: src\patterns/creational/fold.md:82 +msgid "" +"Like the visitor pattern, the fold pattern allows us to separate traversal " +"of a\n" +"data structure from the operations performed to each node." +msgstr "" + +#: src\patterns/creational/fold.md:87 +msgid "" +"Mapping data structures in this fashion is common in functional languages. " +"In OO\n" +"languages, it would be more common to mutate the data structure in place. " +"The\n" +"'functional' approach is common in Rust, mostly due to the preference for\n" +"immutability. Using fresh data structures, rather than mutating old ones, " +"makes\n" +"reasoning about the code easier in most circumstances." +msgstr "" + +#: src\patterns/creational/fold.md:93 +msgid "" +"The trade-off between efficiency and reusability can be tweaked by changing " +"how\n" +"nodes are accepted by the `fold_*` methods." +msgstr "" + +#: src\patterns/creational/fold.md:96 +msgid "" +"In the above example we operate on `Box` pointers. Since these own their " +"data\n" +"exclusively, the original copy of the data structure cannot be re-used. On " +"the\n" +"other hand if a node is not changed, reusing it is very efficient." +msgstr "" + +#: src\patterns/creational/fold.md:100 +msgid "" +"If we were to operate on borrowed references, the original data structure " +"can be\n" +"reused; however, a node must be cloned even if unchanged, which can be\n" +"expensive." +msgstr "" + +#: src\patterns/creational/fold.md:104 +msgid "" +"Using a reference counted pointer gives the best of both worlds - we can " +"reuse\n" +"the original data structure, and we don't need to clone unchanged nodes. " +"However,\n" +"they are less ergonomic to use and mean that the data structures cannot be\n" +"mutable." +msgstr "" + +#: src\patterns/creational/fold.md:111 +msgid "" +"Iterators have a `fold` method, however this folds a data structure into a\n" +"value, rather than into a new data structure. An iterator's `map` is more " +"like\n" +"this fold pattern." +msgstr "" + +#: src\patterns/creational/fold.md:115 +msgid "" +"In other languages, fold is usually used in the sense of Rust's iterators,\n" +"rather than this pattern. Some functional languages have powerful constructs " +"for\n" +"performing flexible maps over data structures." +msgstr "" + +#: src\patterns/creational/fold.md:119 +msgid "" +"The [visitor](../behavioural/visitor.md) pattern is closely related to " +"fold.\n" +"They share the concept of walking a data structure performing an operation " +"on\n" +"each node. However, the visitor does not create a new data structure nor " +"consume\n" +"the old one." +msgstr "" + +#: src\patterns/structural/intro.md:1 +msgid "# Structural Patterns" +msgstr "" + +#: src\patterns/structural/intro.md:3 +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +msgstr "" + +#: src\patterns/structural/intro.md:5 +msgid "" +"> Design patterns that ease the design by identifying a simple way to " +"realize relationships\n" +"> among entities." +msgstr "" + +#: src\patterns/structural/compose-structs.md:1 +msgid "# Compose structs together for better borrowing" +msgstr "" + +#: src\patterns/structural/compose-structs.md:3 +msgid "TODO - this is not a very snappy name" +msgstr "" + +#: src\patterns/structural/compose-structs.md:7 +msgid "" +"Sometimes a large struct will cause issues with the borrow checker - " +"although\n" +"fields can be borrowed independently, sometimes the whole struct ends up " +"being\n" +"used at once, preventing other uses. A solution might be to decompose the " +"struct\n" +"into several smaller structs. Then compose these together into the original\n" +"struct. Then each struct can be borrowed separately and have more flexible\n" +"behaviour." +msgstr "" + +#: src\patterns/structural/compose-structs.md:14 +msgid "" +"This will often lead to a better design in other ways: applying this design\n" +"pattern often reveals smaller units of functionality." +msgstr "" + +#: src\patterns/structural/compose-structs.md:19 +msgid "" +"Here is a contrived example of where the borrow checker foils us in our plan " +"to\n" +"use a struct:" +msgstr "" + +#: src\patterns/structural/compose-structs.md:22 +msgid "" +"```rust\n" +"struct A {\n" +" f1: u32,\n" +" f2: u32,\n" +" f3: u32,\n" +"}\n" +"\n" +"fn foo(a: &mut A) -> &u32 { &a.f2 }\n" +"fn bar(a: &mut A) -> u32 { a.f1 + a.f3 }\n" +"\n" +"fn baz(a: &mut A) {\n" +" // The later usage of x causes a to be borrowed for the rest of the " +"function.\n" +" let x = foo(a);\n" +" // Borrow checker error:\n" +" // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than " +"once\n" +" // at a time\n" +" println!(\"{}\", x);\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/structural/compose-structs.md:42 +msgid "" +"We can apply this design pattern and refactor `A` into two smaller structs, " +"thus\n" +"solving the borrow checking issue:" +msgstr "" + +#: src\patterns/structural/compose-structs.md:45 +msgid "" +"```rust\n" +"// A is now composed of two structs - B and C.\n" +"struct A {\n" +" b: B,\n" +" c: C,\n" +"}\n" +"struct B {\n" +" f2: u32,\n" +"}\n" +"struct C {\n" +" f1: u32,\n" +" f3: u32,\n" +"}\n" +"\n" +"// These functions take a B or C, rather than A.\n" +"fn foo(b: &mut B) -> &u32 { &b.f2 }\n" +"fn bar(c: &mut C) -> u32 { c.f1 + c.f3 }\n" +"\n" +"fn baz(a: &mut A) {\n" +" let x = foo(&mut a.b);\n" +" // Now it's OK!\n" +" let y = bar(&mut a.c);\n" +" println!(\"{}\", x);\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/structural/compose-structs.md:73 +msgid "TODO Why and where you should use the pattern" +msgstr "" + +#: src\patterns/structural/compose-structs.md:77 +msgid "Lets you work around limitations in the borrow checker." +msgstr "" + +#: src\patterns/structural/compose-structs.md:79 +msgid "Often produces a better design." +msgstr "" + +#: src\patterns/structural/compose-structs.md:83 +msgid "Leads to more verbose code." +msgstr "" + +#: src\patterns/structural/compose-structs.md:85 +msgid "" +"Sometimes, the smaller structs are not good abstractions, and so we end up " +"with\n" +"a worse design. That is probably a 'code smell', indicating that the " +"program\n" +"should be refactored in some way." +msgstr "" + +#: src\patterns/structural/compose-structs.md:91 +msgid "" +"This pattern is not required in languages that don't have a borrow checker, " +"so\n" +"in that sense is unique to Rust. However, making smaller units of " +"functionality\n" +"often leads to cleaner code: a widely acknowledged principle of software\n" +"engineering, independent of the language." +msgstr "" + +#: src\patterns/structural/compose-structs.md:96 +msgid "" +"This pattern relies on Rust's borrow checker to be able to borrow fields\n" +"independently of each other. In the example, the borrow checker knows that " +"`a.b`\n" +"and `a.c` are distinct and can be borrowed independently, it does not try " +"to\n" +"borrow all of `a`, which would make this pattern useless." +msgstr "" + +#: src\patterns/structural/small-crates.md:1 +msgid "# Prefer small crates" +msgstr "" + +#: src\patterns/structural/small-crates.md:5 +msgid "Prefer small crates that do one thing well." +msgstr "" + +#: src\patterns/structural/small-crates.md:7 +msgid "" +"Cargo and crates.io make it easy to add third-party libraries, much more so " +"than\n" +"in say C or C++. Moreover, since packages on crates.io cannot be edited or " +"removed\n" +"after publication, any build that works now should continue to work in the " +"future.\n" +"We should take advantage of this tooling, and use smaller, more fine-grained " +"dependencies." +msgstr "" + +#: src\patterns/structural/small-crates.md:14 +msgid "" +"- Small crates are easier to understand, and encourage more modular code.\n" +"- Crates allow for re-using code between projects.\n" +" For example, the `url` crate was developed as part of the Servo browser " +"engine,\n" +" but has since found wide use outside the project.\n" +"- Since the compilation unit\n" +" of Rust is the crate, splitting a project into multiple crates can allow " +"more of\n" +" the code to be built in parallel." +msgstr "" + +#: src\patterns/structural/small-crates.md:24 +msgid "" +"- This can lead to \"dependency hell\", when a project depends on multiple " +"conflicting\n" +" versions of a crate at the same time. For example, the `url` crate has " +"both versions\n" +" 1.0 and 0.5. Since the `Url` from `url:1.0` and the `Url` from `url:0.5` " +"are\n" +" different types, an HTTP client that uses `url:0.5` would not accept `Url` " +"values\n" +" from a web scraper that uses `url:1.0`.\n" +"- Packages on crates.io are not curated. A crate may be poorly written, " +"have\n" +" unhelpful documentation, or be outright malicious.\n" +"- Two small crates may be less optimized than one large one, since the " +"compiler\n" +" does not perform link-time optimization (LTO) by default." +msgstr "" + +#: src\patterns/structural/small-crates.md:36 +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions\n" +"for converting `&T` to `&[T]`." +msgstr "" + +#: src\patterns/structural/small-crates.md:39 +msgid "" +"The [`url`](https://crates.io/crates/url) crate provides tools for working " +"with\n" +"URLs." +msgstr "" + +#: src\patterns/structural/small-crates.md:42 +msgid "" +"The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a " +"function to\n" +"query the number of CPUs on a machine." +msgstr "" + +#: src\patterns/structural/small-crates.md:47 +msgid "- [crates.io: The Rust community crate host](https://crates.io/)" +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:1 +msgid "# Contain unsafety in small modules" +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:5 +msgid "" +"If you have `unsafe` code, create the smallest possible module that can " +"uphold\n" +"the needed invariants to build a minimal safe interface upon the unsafety. " +"Embed\n" +"this into a larger module that contains only safe code and presents an " +"ergonomic\n" +"interface. Note that the outer module can contain unsafe functions and " +"methods\n" +"that call directly into the unsafe code. Users may use this to gain speed " +"benefits." +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:13 +msgid "" +"- This restricts the unsafe code that must be audited\n" +"- Writing the outer module is much easier, since you can count on the " +"guarantees\n" +" of the inner module" +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:19 +msgid "" +"- Sometimes, it may be hard to find a suitable interface.\n" +"- The abstraction may introduce inefficiencies." +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:24 +msgid "" +"- The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe " +"operations\n" +" in submodules, presenting a safe interface to users.\n" +"- `std`'s `String` class is a wrapper over `Vec` with the added " +"invariant\n" +" that the contents must be valid UTF-8. The operations on `String` ensure " +"this\n" +" behavior.\n" +" However, users have the option of using an `unsafe` method to create a " +"`String`,\n" +" in which case the onus is on them to guarantee the validity of the " +"contents." +msgstr "" + +#: src\patterns/structural/unsafe-mods.md:34 +msgid "" +"- [Ralf Jung's Blog about invariants in unsafe code](https://www.ralfj.de/" +"blog/2018/08/22/two-kinds-of-invariants.html)" +msgstr "" + +#: src\patterns/ffi/intro.md:1 +msgid "# FFI Patterns" +msgstr "" + +#: src\patterns/ffi/intro.md:3 +msgid "" +"Writing FFI code is an entire course in itself.\n" +"However, there are several idioms here that can act as pointers, and avoid " +"traps\n" +"for inexperienced users of unsafe Rust." +msgstr "" + +#: src\patterns/ffi/intro.md:7 +msgid "" +"This section contains design patterns that may be useful when doing FFI." +msgstr "" + +#: src\patterns/ffi/intro.md:9 +msgid "" +"1. [Object-Based API](./export.md) design that has good memory safety " +"characteristics,\n" +" and a clean boundary of what is safe and what is unsafe\n" +"\n" +"2. [Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust " +"types\n" +" together into an opaque \"object\"" +msgstr "" + +#: src\patterns/ffi/export.md:1 +msgid "# Object-Based APIs" +msgstr "" + +#: src\patterns/ffi/export.md:5 +msgid "" +"When designing APIs in Rust which are exposed to other languages, there are " +"some\n" +"important design principles which are contrary to normal Rust API design:" +msgstr "" + +#: src\patterns/ffi/export.md:8 +msgid "" +"1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user,\n" +" and _opaque_.\n" +"2. All Transactional data types should be _owned_ by the user, and " +"_transparent_.\n" +"3. All library behavior should be functions acting upon Encapsulated types.\n" +"4. All library behavior should be encapsulated into types not based on " +"structure,\n" +" but _provenance/lifetime_." +msgstr "" + +#: src\patterns/ffi/export.md:17 +msgid "" +"Rust has built-in FFI support to other languages.\n" +"It does this by providing a way for crate authors to provide C-compatible " +"APIs\n" +"through different ABIs (though that is unimportant to this practice)." +msgstr "" + +#: src\patterns/ffi/export.md:21 +msgid "" +"Well-designed Rust FFI follows C API design principles, while compromising " +"the\n" +"design in Rust as little as possible. There are three goals with any foreign " +"API:" +msgstr "" + +#: src\patterns/ffi/export.md:24 +msgid "" +"1. Make it easy to use in the target language.\n" +"2. Avoid the API dictating internal unsafety on the Rust side as much as " +"possible.\n" +"3. Keep the potential for memory unsafety and Rust `undefined behaviour` as " +"small\n" +" as possible." +msgstr "" + +#: src\patterns/ffi/export.md:29 +msgid "" +"Rust code must trust the memory safety of the foreign language beyond a " +"certain\n" +"point. However, every bit of `unsafe` code on the Rust side is an " +"opportunity for\n" +"bugs, or to exacerbate `undefined behaviour`." +msgstr "" + +#: src\patterns/ffi/export.md:33 +msgid "" +"For example, if a pointer provenance is wrong, that may be a segfault due " +"to\n" +"invalid memory access. But if it is manipulated by unsafe code, it could " +"become\n" +"full-blown heap corruption." +msgstr "" + +#: src\patterns/ffi/export.md:37 +msgid "" +"The Object-Based API design allows for writing shims that have good memory " +"safety\n" +"characteristics, and a clean boundary of what is safe and what is `unsafe`." +msgstr "" + +#: src\patterns/ffi/export.md:42 +msgid "" +"The POSIX standard defines the API to access an on-file database, known as " +"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/" +"ndbm.h).\n" +"It is an excellent example of an \"object-based\" API." +msgstr "" + +#: src\patterns/ffi/export.md:45 +msgid "" +"Here is the definition in C, which hopefully should be easy to read for " +"those\n" +"involved in FFI. The commentary below should help explain it for those who\n" +"miss the subtleties." +msgstr "" + +#: src\patterns/ffi/export.md:49 +msgid "" +"```C\n" +"struct DBM;\n" +"typedef struct { void *dptr, size_t dsize } datum;\n" +"\n" +"int dbm_clearerr(DBM *);\n" +"void dbm_close(DBM *);\n" +"int dbm_delete(DBM *, datum);\n" +"int dbm_error(DBM *);\n" +"datum dbm_fetch(DBM *, datum);\n" +"datum dbm_firstkey(DBM *);\n" +"datum dbm_nextkey(DBM *);\n" +"DBM *dbm_open(const char *, int, mode_t);\n" +"int dbm_store(DBM *, datum, datum, int);\n" +"```" +msgstr "" + +#: src\patterns/ffi/export.md:64 +msgid "This API defines two types: `DBM` and `datum`." +msgstr "" + +#: src\patterns/ffi/export.md:66 +msgid "" +"The `DBM` type was called an \"encapsulated\" type above.\n" +"It is designed to contain internal state, and acts as an entry point for " +"the\n" +"library's behavior." +msgstr "" + +#: src\patterns/ffi/export.md:70 +msgid "" +"It is completely opaque to the user, who cannot create a `DBM` themselves " +"since\n" +"they don't know its size or layout. Instead, they must call `dbm_open`, and " +"that\n" +"only gives them _a pointer to one_." +msgstr "" + +#: src\patterns/ffi/export.md:74 +msgid "" +"This means all `DBM`s are \"owned\" by the library in a Rust sense.\n" +"The internal state of unknown size is kept in memory controlled by the " +"library,\n" +"not the user. The user can only manage its life cycle with `open` and " +"`close`,\n" +"and perform operations on it with the other functions." +msgstr "" + +#: src\patterns/ffi/export.md:79 +msgid "" +"The `datum` type was called a \"transactional\" type above.\n" +"It is designed to facilitate the exchange of information between the library " +"and\n" +"its user." +msgstr "" + +#: src\patterns/ffi/export.md:83 +msgid "" +"The database is designed to store \"unstructured data\", with no pre-defined " +"length\n" +"or meaning. As a result, the `datum` is the C equivalent of a Rust slice: a " +"bunch\n" +"of bytes, and a count of how many there are. The main difference is that " +"there is\n" +"no type information, which is what `void` indicates." +msgstr "" + +#: src\patterns/ffi/export.md:88 +msgid "" +"Keep in mind that this header is written from the library's point of view.\n" +"The user likely has some type they are using, which has a known size.\n" +"But the library does not care, and by the rules of C casting, any type " +"behind a\n" +"pointer can be cast to `void`." +msgstr "" + +#: src\patterns/ffi/export.md:93 +msgid "" +"As noted earlier, this type is _transparent_ to the user. But also, this " +"type is\n" +"_owned_ by the user.\n" +"This has subtle ramifications, due to that pointer inside it.\n" +"The question is, who owns the memory that pointer points to?" +msgstr "" + +#: src\patterns/ffi/export.md:98 +msgid "" +"The answer for best memory safety is, \"the user\".\n" +"But in cases such as retrieving a value, the user does not know how to " +"allocate\n" +"it correctly (since they don't know how long the value is). In this case, " +"the library\n" +"code is expected to use the heap that the user has access to -- such as the " +"C library\n" +"`malloc` and `free` -- and then _transfer ownership_ in the Rust sense." +msgstr "" + +#: src\patterns/ffi/export.md:104 +msgid "" +"This may all seem speculative, but this is what a pointer means in C.\n" +"It means the same thing as Rust: \"user defined lifetime.\"\n" +"The user of the library needs to read the documentation in order to use it " +"correctly.\n" +"That said, there are some decisions that have fewer or greater consequences " +"if users\n" +"do it wrong. Minimizing those are what this best practice is about, and the " +"key\n" +"is to _transfer ownership of everything that is transparent_." +msgstr "" + +#: src\patterns/ffi/export.md:113 +msgid "" +"This minimizes the number of memory safety guarantees the user must uphold " +"to a\n" +"relatively small number:" +msgstr "" + +#: src\patterns/ffi/export.md:116 +msgid "" +"1. Do not call any function with a pointer not returned by `dbm_open` " +"(invalid\n" +" access or corruption).\n" +"2. Do not call any function on a pointer after close (use after free).\n" +"3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of " +"memory\n" +" at the advertised length." +msgstr "" + +#: src\patterns/ffi/export.md:122 +msgid "" +"In addition, it avoids a lot of pointer provenance issues.\n" +"To understand why, let us consider an alternative in some depth: key " +"iteration." +msgstr "" + +#: src\patterns/ffi/export.md:125 +msgid "" +"Rust is well known for its iterators.\n" +"When implementing one, the programmer makes a separate type with a bounded " +"lifetime\n" +"to its owner, and implements the `Iterator` trait." +msgstr "" + +#: src\patterns/ffi/export.md:129 +msgid "Here is how iteration would be done in Rust for `DBM`:" +msgstr "" + +#: src\patterns/ffi/export.md:131 +msgid "" +"```rust,ignore\n" +"struct Dbm { ... }\n" +"\n" +"impl Dbm {\n" +" /* ... */\n" +" pub fn keys<'it>(&'it self) -> DbmKeysIter<'it> { ... }\n" +" /* ... */\n" +"}\n" +"\n" +"struct DbmKeysIter<'it> {\n" +" owner: &'it Dbm,\n" +"}\n" +"\n" +"impl<'it> Iterator for DbmKeysIter<'it> { ... }\n" +"```" +msgstr "" + +#: src\patterns/ffi/export.md:147 +msgid "" +"This is clean, idiomatic, and safe. thanks to Rust's guarantees.\n" +"However, consider what a straightforward API translation would look like:" +msgstr "" + +#: src\patterns/ffi/export.md:150 +msgid "" +"```rust,ignore\n" +"#[no_mangle]\n" +"pub extern \"C\" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter {\n" +" // THIS API IS A BAD IDEA! For real applications, use object-based " +"design instead.\n" +"}\n" +"#[no_mangle]\n" +"pub extern \"C\" fn dbm_iter_next(\n" +" iter: *mut DbmKeysIter,\n" +" key_out: *const datum\n" +") -> libc::c_int {\n" +" // THIS API IS A BAD IDEA! For real applications, use object-based " +"design instead.\n" +"}\n" +"#[no_mangle]\n" +"pub extern \"C\" fn dbm_iter_del(*mut DbmKeysIter) {\n" +" // THIS API IS A BAD IDEA! For real applications, use object-based " +"design instead.\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/ffi/export.md:168 +msgid "" +"This API loses a key piece of information: the lifetime of the iterator must " +"not\n" +"exceed the lifetime of the `Dbm` object that owns it. A user of the library " +"could\n" +"use it in a way which causes the iterator to outlive the data it is " +"iterating on,\n" +"resulting in reading uninitialized memory." +msgstr "" + +#: src\patterns/ffi/export.md:173 +msgid "" +"This example written in C contains a bug that will be explained afterwards:" +msgstr "" + +#: src\patterns/ffi/export.md:175 +msgid "" +"```C\n" +"int count_key_sizes(DBM *db) {\n" +" // DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG!\n" +" datum key;\n" +" int len = 0;\n" +"\n" +" if (!dbm_iter_new(db)) {\n" +" dbm_close(db);\n" +" return -1;\n" +" }\n" +"\n" +" int l;\n" +" while ((l = dbm_iter_next(owner, &key)) >= 0) { // an error is indicated " +"by -1\n" +" free(key.dptr);\n" +" len += key.dsize;\n" +" if (l == 0) { // end of the iterator\n" +" dbm_close(owner);\n" +" }\n" +" }\n" +" if l >= 0 {\n" +" return -1;\n" +" } else {\n" +" return len;\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/ffi/export.md:202 +msgid "" +"This bug is a classic. Here's what happens when the iterator returns the\n" +"end-of-iteration marker:" +msgstr "" + +#: src\patterns/ffi/export.md:205 +msgid "" +"1. The loop condition sets `l` to zero, and enters the loop because `0 >= " +"0`.\n" +"2. The length is incremented, in this case by zero.\n" +"3. The if statement is true, so the database is closed. There should be a " +"break\n" +" statement here.\n" +"4. The loop condition executes again, causing a `next` call on the closed " +"object." +msgstr "" + +#: src\patterns/ffi/export.md:211 +msgid "" +"The worst part about this bug?\n" +"If the Rust implementation was careful, this code will work most of the " +"time!\n" +"If the memory for the `Dbm` object is not immediately reused, an internal " +"check\n" +"will almost certainly fail, resulting in the iterator returning a `-1` " +"indicating\n" +"an error. But occasionally, it will cause a segmentation fault, or even " +"worse,\n" +"nonsensical memory corruption!" +msgstr "" + +#: src\patterns/ffi/export.md:218 +msgid "" +"None of this can be avoided by Rust.\n" +"From its perspective, it put those objects on its heap, returned pointers to " +"them,\n" +"and gave up control of their lifetimes. The C code simply must \"play nice\"." +msgstr "" + +#: src\patterns/ffi/export.md:222 +msgid "" +"The programmer must read and understand the API documentation.\n" +"While some consider that par for the course in C, a good API design can " +"mitigate\n" +"this risk. The POSIX API for `DBM` did this by _consolidating the ownership_ " +"of\n" +"the iterator with its parent:" +msgstr "" + +#: src\patterns/ffi/export.md:227 +msgid "" +"```C\n" +"datum dbm_firstkey(DBM *);\n" +"datum dbm_nextkey(DBM *);\n" +"```" +msgstr "" + +#: src\patterns/ffi/export.md:232 +msgid "" +"Thus, all the lifetimes were bound together, and such unsafety was prevented." +msgstr "" + +#: src\patterns/ffi/export.md:236 +msgid "" +"However, this design choice also has a number of drawbacks, which should be\n" +"considered as well." +msgstr "" + +#: src\patterns/ffi/export.md:239 +msgid "" +"First, the API itself becomes less expressive.\n" +"With POSIX DBM, there is only one iterator per object, and every call " +"changes\n" +"its state. This is much more restrictive than iterators in almost any " +"language,\n" +"even though it is safe. Perhaps with other related objects, whose lifetimes " +"are\n" +"less hierarchical, this limitation is more of a cost than the safety." +msgstr "" + +#: src\patterns/ffi/export.md:245 +msgid "" +"Second, depending on the relationships of the API's parts, significant " +"design effort\n" +"may be involved. Many of the easier design points have other patterns " +"associated\n" +"with them:" +msgstr "" + +#: src\patterns/ffi/export.md:249 +msgid "" +"- [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types " +"together\n" +" into an opaque \"object\"\n" +"\n" +"- [FFI Error Passing](../../idioms/ffi/errors.md) explains error handling " +"with integer\n" +" codes and sentinel return values (such as `NULL` pointers)\n" +"\n" +"- [Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) allows " +"accepting\n" +" strings with minimal unsafe code, and is easier to get right than\n" +" [Passing Strings to FFI](../../idioms/ffi/passing-strings.md)" +msgstr "" + +#: src\patterns/ffi/export.md:259 +msgid "" +"However, not every API can be done this way.\n" +"It is up to the best judgement of the programmer as to who their audience is." +msgstr "" + +#: src\patterns/ffi/wrappers.md:1 +msgid "# Type Consolidation into Wrappers" +msgstr "" + +#: src\patterns/ffi/wrappers.md:5 +msgid "" +"This pattern is designed to allow gracefully handling multiple related " +"types,\n" +"while minimizing the surface area for memory unsafety." +msgstr "" + +#: src\patterns/ffi/wrappers.md:8 +msgid "" +"One of the cornerstones of Rust's aliasing rules is lifetimes.\n" +"This ensures that many patterns of access between types can be memory safe,\n" +"data race safety included." +msgstr "" + +#: src\patterns/ffi/wrappers.md:12 +msgid "" +"However, when Rust types are exported to other languages, they are usually " +"transformed\n" +"into pointers. In Rust, a pointer means \"the user manages the lifetime of " +"the pointee.\"\n" +"It is their responsibility to avoid memory unsafety." +msgstr "" + +#: src\patterns/ffi/wrappers.md:16 +msgid "" +"Some level of trust in the user code is thus required, notably around use-" +"after-free\n" +"which Rust can do nothing about. However, some API designs place higher " +"burdens\n" +"than others on the code written in the other language." +msgstr "" + +#: src\patterns/ffi/wrappers.md:20 +msgid "" +"The lowest risk API is the \"consolidated wrapper\", where all possible " +"interactions\n" +"with an object are folded into a \"wrapper type\", while keeping the Rust " +"API clean." +msgstr "" + +#: src\patterns/ffi/wrappers.md:25 +msgid "" +"To understand this, let us look at a classic example of an API to export: " +"iteration\n" +"through a collection." +msgstr "" + +#: src\patterns/ffi/wrappers.md:28 +msgid "That API looks like this:" +msgstr "" + +#: src\patterns/ffi/wrappers.md:30 +msgid "" +"1. The iterator is initialized with `first_key`.\n" +"2. Each call to `next_key` will advance the iterator.\n" +"3. Calls to `next_key` if the iterator is at the end will do nothing.\n" +"4. As noted above, the iterator is \"wrapped into\" the collection (unlike " +"the native\n" +" Rust API)." +msgstr "" + +#: src\patterns/ffi/wrappers.md:36 +msgid "" +"If the iterator implements `nth()` efficiently, then it is possible to make " +"it\n" +"ephemeral to each function call:" +msgstr "" + +#: src\patterns/ffi/wrappers.md:39 +msgid "" +"```rust,ignore\n" +"struct MySetWrapper {\n" +" myset: MySet,\n" +" iter_next: usize,\n" +"}\n" +"\n" +"impl MySetWrapper {\n" +" pub fn first_key(&mut self) -> Option<&Key> {\n" +" self.iter_next = 0;\n" +" self.next_key()\n" +" }\n" +" pub fn next_key(&mut self) -> Option<&Key> {\n" +" if let Some(next) = self.myset.keys().nth(self.iter_next) {\n" +" self.iter_next += 1;\n" +" Some(next)\n" +" } else {\n" +" None\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/ffi/wrappers.md:61 +msgid "As a result, the wrapper is simple and contains no `unsafe` code." +msgstr "" + +#: src\patterns/ffi/wrappers.md:65 +msgid "" +"This makes APIs safer to use, avoiding issues with lifetimes between types.\n" +"See [Object-Based APIs](./export.md) for more on the advantages and " +"pitfalls\n" +"this avoids." +msgstr "" + +#: src\patterns/ffi/wrappers.md:71 +msgid "" +"Often, wrapping types is quite difficult, and sometimes a Rust API " +"compromise\n" +"would make things easier." +msgstr "" + +#: src\patterns/ffi/wrappers.md:74 +msgid "" +"As an example, consider an iterator which does not efficiently implement " +"`nth()`.\n" +"It would definitely be worth putting in special logic to make the object " +"handle\n" +"iteration internally, or to support a different access pattern efficiently " +"that\n" +"only the Foreign Function API will use." +msgstr "" + +#: src\patterns/ffi/wrappers.md:79 +msgid "### Trying to Wrap Iterators (and Failing)" +msgstr "" + +#: src\patterns/ffi/wrappers.md:81 +msgid "" +"To wrap any type of iterator into the API correctly, the wrapper would need " +"to\n" +"do what a C version of the code would do: erase the lifetime of the " +"iterator,\n" +"and manage it manually." +msgstr "" + +#: src\patterns/ffi/wrappers.md:85 +msgid "Suffice it to say, this is _incredibly_ difficult." +msgstr "" + +#: src\patterns/ffi/wrappers.md:87 +msgid "Here is an illustration of just _one_ pitfall." +msgstr "" + +#: src\patterns/ffi/wrappers.md:89 +msgid "A first version of `MySetWrapper` would look like this:" +msgstr "" + +#: src\patterns/ffi/wrappers.md:91 +msgid "" +"```rust,ignore\n" +"struct MySetWrapper {\n" +" myset: MySet,\n" +" iter_next: usize,\n" +" // created from a transmuted Box\n" +" iterator: Option>>,\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/ffi/wrappers.md:100 +msgid "" +"With `transmute` being used to extend a lifetime, and a pointer to hide it,\n" +"it's ugly already. But it gets even worse: _any other operation can cause\n" +"Rust `undefined behaviour`_." +msgstr "" + +#: src\patterns/ffi/wrappers.md:104 +msgid "" +"Consider that the `MySet` in the wrapper could be manipulated by other\n" +"functions during iteration, such as storing a new value to the key it was\n" +"iterating over. The API doesn't discourage this, and in fact some similar C\n" +"libraries expect it." +msgstr "" + +#: src\patterns/ffi/wrappers.md:109 +msgid "A simple implementation of `myset_store` would be:" +msgstr "" + +#: src\patterns/ffi/wrappers.md:111 +msgid "" +"```rust,ignore\n" +"pub mod unsafe_module {\n" +"\n" +" // other module content\n" +"\n" +" pub fn myset_store(\n" +" myset: *mut MySetWrapper,\n" +" key: datum,\n" +" value: datum) -> libc::c_int {\n" +"\n" +" // DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM.\n" +"\n" +" let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in " +"here!\n" +" &mut (*myset).myset\n" +" };\n" +"\n" +" /* ...check and cast key and value data... */\n" +"\n" +" match myset.store(casted_key, casted_value) {\n" +" Ok(_) => 0,\n" +" Err(e) => e.into()\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\patterns/ffi/wrappers.md:137 +msgid "" +"If the iterator exists when this function is called, we have violated one of " +"Rust's\n" +"aliasing rules. According to Rust, the mutable reference in this block must " +"have\n" +"_exclusive_ access to the object. If the iterator simply exists, it's not " +"exclusive,\n" +"so we have `undefined behaviour`! " +msgstr "" + +#: src\patterns/ffi/wrappers.md:142 +msgid "" +"To avoid this, we must have a way of ensuring that mutable reference really " +"is exclusive.\n" +"That basically means clearing out the iterator's shared reference while it " +"exists,\n" +"and then reconstructing it. In most cases, that will still be less efficient " +"than\n" +"the C version." +msgstr "" + +#: src\patterns/ffi/wrappers.md:147 +msgid "" +"Some may ask: how can C do this more efficiently?\n" +"The answer is, it cheats. Rust's aliasing rules are the problem, and C " +"simply ignores\n" +"them for its pointers. In exchange, it is common to see code that is " +"declared\n" +"in the manual as \"not thread safe\" under some or all circumstances. In " +"fact,\n" +"the [GNU C library](https://manpages.debian.org/buster/manpages/" +"attributes.7.en.html)\n" +"has an entire lexicon dedicated to concurrent behavior!" +msgstr "" + +#: src\patterns/ffi/wrappers.md:154 +msgid "" +"Rust would rather make everything memory safe all the time, for both safety " +"and\n" +"optimizations that C code cannot attain. Being denied access to certain " +"shortcuts\n" +"is the price Rust programmers need to pay." +msgstr "" + +#: src\patterns/ffi/wrappers.md:158 +msgid "" +"For the C programmers out there scratching their heads, the iterator need\n" +"not be read _during_ this code cause the UB. The exclusivity rule also " +"enables\n" +"compiler optimizations which may cause inconsistent observations by the " +"iterator's\n" +"shared reference (e.g. stack spills or reordering instructions for " +"efficiency).\n" +"These observations may happen _any time after_ the mutable reference is " +"created." +msgstr "" + +#: src\anti_patterns/index.md:1 +msgid "# Anti-patterns" +msgstr "" + +#: src\anti_patterns/index.md:3 +msgid "" +"An [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern) is a solution " +"to\n" +"a \"recurring problem that is usually ineffective and risks being highly\n" +"counterproductive\". Just as valuable as knowing how to solve a problem, is\n" +"knowing how _not_ to solve it. Anti-patterns give us great counter-examples " +"to\n" +"consider relative to design patterns. Anti-patterns are not confined to " +"code.\n" +"For example, a process can be an anti-pattern, too." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:1 +msgid "# Clone to satisfy the borrow checker" +msgstr "" + +#: src\anti_patterns/borrow_clone.md:5 +msgid "" +"The borrow checker prevents Rust users from developing otherwise unsafe code " +"by\n" +"ensuring that either: only one mutable reference exists, or potentially many " +"but\n" +"all immutable references exist. If the code written does not hold true to " +"these\n" +"conditions, this anti-pattern arises when the developer resolves the " +"compiler\n" +"error by cloning the variable." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:13 +msgid "" +"```rust\n" +"// define any variable\n" +"let mut x = 5;\n" +"\n" +"// Borrow `x` -- but clone it first\n" +"let y = &mut (x.clone());\n" +"\n" +"// without the x.clone() two lines prior, this line would fail on compile " +"as\n" +"// x has been borrowed\n" +"// thanks to x.clone(), x was never borrowed, and this line will run.\n" +"println!(\"{}\", x);\n" +"\n" +"// perform some action on the borrow to prevent rust from optimizing this\n" +"//out of existence\n" +"*y += 1;\n" +"```" +msgstr "" + +#: src\anti_patterns/borrow_clone.md:32 +msgid "" +"It is tempting, particularly for beginners, to use this pattern to resolve\n" +"confusing issues with the borrow checker. However, there are serious\n" +"consequences. Using `.clone()` causes a copy of the data to be made. Any " +"changes\n" +"between the two are not synchronized -- as if two completely separate " +"variables\n" +"exist." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:38 +msgid "" +"There are special cases -- `Rc` is designed to handle clones " +"intelligently.\n" +"It internally manages exactly one copy of the data, and cloning it will " +"only\n" +"clone the reference." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:42 +msgid "" +"There is also `Arc` which provides shared ownership of a value of type T\n" +"that is allocated in the heap. Invoking `.clone()` on `Arc` produces a new " +"`Arc`\n" +"instance, which points to the same allocation on the heap as the source " +"`Arc`,\n" +"while increasing a reference count." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:47 +msgid "" +"In general, clones should be deliberate, with full understanding of the\n" +"consequences. If a clone is used to make a borrow checker error disappear,\n" +"that's a good indication this anti-pattern may be in use." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:51 +msgid "" +"Even though `.clone()` is an indication of a bad pattern, sometimes\n" +"**it is fine to write inefficient code**, in cases such as when:" +msgstr "" + +#: src\anti_patterns/borrow_clone.md:54 +msgid "" +"- the developer is still new to ownership\n" +"- the code doesn't have great speed or memory constraints\n" +" (like hackathon projects or prototypes)\n" +"- satisfying the borrow checker is really complicated, and you prefer to\n" +" optimize readability over performance" +msgstr "" + +#: src\anti_patterns/borrow_clone.md:60 +msgid "" +"If an unnecessary clone is suspected, The [Rust Book's chapter on Ownership]" +"(https://doc.rust-lang.org/book/ownership.html)\n" +"should be understood fully before assessing whether the clone is required or " +"not." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:63 +msgid "" +"Also be sure to always run `cargo clippy` in your project, which will detect " +"some\n" +"cases in which `.clone()` is not necessary, like [1](https://rust-" +"lang.github.io/rust-clippy/master/index.html#redundant_clone),\n" +"[2](https://rust-lang.github.io/rust-clippy/master/" +"index.html#clone_on_copy),\n" +"[3](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) or " +"[4](https://rust-lang.github.io/rust-clippy/master/" +"index.html#clone_double_ref)." +msgstr "" + +#: src\anti_patterns/borrow_clone.md:70 +msgid "" +"- [`mem::{take(_), replace(_)}` to keep owned values in changed enums](../" +"idioms/mem-replace.md)\n" +"- [`Rc` documentation, which handles .clone() intelligently](http://" +"doc.rust-lang.org/std/rc/)\n" +"- [`Arc` documentation, a thread-safe reference-counting pointer](https://" +"doc.rust-lang.org/std/sync/struct.Arc.html)\n" +"- [Tricks with ownership in Rust](https://web.archive.org/web/20210120233744/" +"https://xion.io/post/code/rust-borrowchk-tricks.html)" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:1 +msgid "# `#![deny(warnings)]`" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:5 +msgid "" +"A well-intentioned crate author wants to ensure their code builds without\n" +"warnings. So they annotate their crate root with the following:" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:10 +msgid "" +"```rust\n" +"#![deny(warnings)]\n" +"\n" +"// All is well.\n" +"```" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:18 +msgid "It is short and will stop the build if anything is amiss." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:20 +msgid "## Drawbacks" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:22 +msgid "" +"By disallowing the compiler to build with warnings, a crate author opts out " +"of\n" +"Rust's famed stability. Sometimes new features or old misfeatures need a " +"change\n" +"in how things are done, thus lints are written that `warn` for a certain " +"grace\n" +"period before being turned to `deny`." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:27 +msgid "" +"For example, it was discovered that a type could have two `impl`s with the " +"same\n" +"method. This was deemed a bad idea, but in order to make the transition " +"smooth,\n" +"the `overlapping-inherent-impls` lint was introduced to give a warning to " +"those\n" +"stumbling on this fact, before it becomes a hard error in a future release." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:32 +msgid "" +"Also sometimes APIs get deprecated, so their use will emit a warning where\n" +"before there was none." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:35 +msgid "" +"All this conspires to potentially break the build whenever something changes." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:37 +msgid "" +"Furthermore, crates that supply additional lints (e.g. [rust-clippy]) can " +"no\n" +"longer be used unless the annotation is removed. This is mitigated with\n" +"[--cap-lints]. The `--cap-lints=warn` command line argument, turns all " +"`deny`\n" +"lint errors into warnings." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:42 +#: src\functional/generics-type-classes.md:227 +msgid "## Alternatives" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:44 +msgid "" +"There are two ways of tackling this problem: First, we can decouple the " +"build\n" +"setting from the code, and second, we can name the lints we want to deny\n" +"explicitly." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:48 +msgid "The following command line will build with all warnings set to `deny`:" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:50 +msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:52 +msgid "" +"This can be done by any individual developer (or be set in a CI tool like\n" +"Travis, but remember that this may break the build when something changes)\n" +"without requiring a change to the code." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:56 +msgid "" +"Alternatively, we can specify the lints that we want to `deny` in the code.\n" +"Here is a list of warning lints that is (hopefully) safe to deny (as of " +"Rustc 1.48.0):" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:59 +msgid "" +"```rust,ignore\n" +"#![deny(bad_style,\n" +" const_err,\n" +" dead_code,\n" +" improper_ctypes,\n" +" non_shorthand_field_patterns,\n" +" no_mangle_generic_items,\n" +" overflowing_literals,\n" +" path_statements,\n" +" patterns_in_fns_without_body,\n" +" private_in_public,\n" +" unconditional_recursion,\n" +" unused,\n" +" unused_allocation,\n" +" unused_comparisons,\n" +" unused_parens,\n" +" while_true)]\n" +"```" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:78 +msgid "" +"In addition, the following `allow`ed lints may be a good idea to `deny`:" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:80 +msgid "" +"```rust,ignore\n" +"#![deny(missing_debug_implementations,\n" +" missing_docs,\n" +" trivial_casts,\n" +" trivial_numeric_casts,\n" +" unused_extern_crates,\n" +" unused_import_braces,\n" +" unused_qualifications,\n" +" unused_results)]\n" +"```" +msgstr "" + +#: src\anti_patterns/deny-warnings.md:91 +msgid "Some may also want to add `missing-copy-implementations` to their list." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:93 +msgid "" +"Note that we explicitly did not add the `deprecated` lint, as it is fairly\n" +"certain that there will be more deprecated APIs in the future." +msgstr "" + +#: src\anti_patterns/deny-warnings.md:98 +msgid "" +"- [A collection of all clippy lints](https://rust-lang.github.io/rust-clippy/" +"master)\n" +"- [deprecate attribute] documentation\n" +"- Type `rustc -W help` for a list of lints on your system. Also type\n" +" `rustc --help` for a general list of options\n" +"- [rust-clippy] is a collection of lints for better Rust code" +msgstr "" + +#: src\anti_patterns/deref.md:1 +msgid "# `Deref` polymorphism" +msgstr "" + +#: src\anti_patterns/deref.md:5 +msgid "" +"Misuse the `Deref` trait to emulate inheritance between structs, and thus " +"reuse\n" +"methods." +msgstr "" + +#: src\anti_patterns/deref.md:10 +msgid "" +"Sometimes we want to emulate the following common pattern from OO languages " +"such\n" +"as Java:" +msgstr "" + +#: src\anti_patterns/deref.md:13 +msgid "" +"```java\n" +"class Foo {\n" +" void m() { ... }\n" +"}\n" +"\n" +"class Bar extends Foo {}\n" +"\n" +"public static void main(String[] args) {\n" +" Bar b = new Bar();\n" +" b.m();\n" +"}\n" +"```" +msgstr "" + +#: src\anti_patterns/deref.md:26 +msgid "We can use the deref polymorphism anti-pattern to do so:" +msgstr "" + +#: src\anti_patterns/deref.md:28 +msgid "" +"```rust\n" +"use std::ops::Deref;\n" +"\n" +"struct Foo {}\n" +"\n" +"impl Foo {\n" +" fn m(&self) {\n" +" //..\n" +" }\n" +"}\n" +"\n" +"struct Bar {\n" +" f: Foo,\n" +"}\n" +"\n" +"impl Deref for Bar {\n" +" type Target = Foo;\n" +" fn deref(&self) -> &Foo {\n" +" &self.f\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let b = Bar { f: Foo {} };\n" +" b.m();\n" +"}\n" +"```" +msgstr "" + +#: src\anti_patterns/deref.md:56 +msgid "" +"There is no struct inheritance in Rust. Instead we use composition and " +"include\n" +"an instance of `Foo` in `Bar` (since the field is a value, it is stored " +"inline,\n" +"so if there were fields, they would have the same layout in memory as the " +"Java\n" +"version (probably, you should use `#[repr(C)]` if you want to be sure))." +msgstr "" + +#: src\anti_patterns/deref.md:61 +msgid "" +"In order to make the method call work we implement `Deref` for `Bar` with " +"`Foo`\n" +"as the target (returning the embedded `Foo` field). That means that when we\n" +"dereference a `Bar` (for example, using `*`) then we will get a `Foo`. That " +"is\n" +"pretty weird. Dereferencing usually gives a `T` from a reference to `T`, " +"here we\n" +"have two unrelated types. However, since the dot operator does implicit\n" +"dereferencing, it means that the method call will search for methods on " +"`Foo` as\n" +"well as `Bar`." +msgstr "" + +#: src\anti_patterns/deref.md:71 +msgid "You save a little boilerplate, e.g.," +msgstr "" + +#: src\anti_patterns/deref.md:73 +msgid "" +"```rust,ignore\n" +"impl Bar {\n" +" fn m(&self) {\n" +" self.f.m()\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\anti_patterns/deref.md:83 +msgid "" +"Most importantly this is a surprising idiom - future programmers reading " +"this in\n" +"code will not expect this to happen. That's because we are misusing the " +"`Deref`\n" +"trait rather than using it as intended (and documented, etc.). It's also " +"because\n" +"the mechanism here is completely implicit." +msgstr "" + +#: src\anti_patterns/deref.md:88 +msgid "" +"This pattern does not introduce subtyping between `Foo` and `Bar` like\n" +"inheritance in Java or C++ does. Furthermore, traits implemented by `Foo` " +"are\n" +"not automatically implemented for `Bar`, so this pattern interacts badly " +"with\n" +"bounds checking and thus generic programming." +msgstr "" + +#: src\anti_patterns/deref.md:93 +msgid "" +"Using this pattern gives subtly different semantics from most OO languages " +"with\n" +"regards to `self`. Usually it remains a reference to the sub-class, with " +"this\n" +"pattern it will be the 'class' where the method is defined." +msgstr "" + +#: src\anti_patterns/deref.md:97 +msgid "" +"Finally, this pattern only supports single inheritance, and has no notion " +"of\n" +"interfaces, class-based privacy, or other inheritance-related features. So, " +"it\n" +"gives an experience that will be subtly surprising to programmers used to " +"Java\n" +"inheritance, etc." +msgstr "" + +#: src\anti_patterns/deref.md:104 +msgid "" +"There is no one good alternative. Depending on the exact circumstances it " +"might\n" +"be better to re-implement using traits or to write out the facade methods " +"to\n" +"dispatch to `Foo` manually. We do intend to add a mechanism for inheritance\n" +"similar to this to Rust, but it is likely to be some time before it reaches\n" +"stable Rust. See these [blog](http://aturon.github.io/blog/2015/09/18/" +"reuse/)\n" +"[posts](http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-" +"structs-part-4-extended-enums-and-thin-traits/)\n" +"and this [RFC issue](https://github.com/rust-lang/rfcs/issues/349) for more " +"details." +msgstr "" + +#: src\anti_patterns/deref.md:112 +msgid "" +"The `Deref` trait is designed for the implementation of custom pointer " +"types.\n" +"The intention is that it will take a pointer-to-`T` to a `T`, not convert\n" +"between different types. It is a shame that this isn't (probably cannot be)\n" +"enforced by the trait definition." +msgstr "" + +#: src\anti_patterns/deref.md:117 +msgid "" +"Rust tries to strike a careful balance between explicit and implicit " +"mechanisms,\n" +"favouring explicit conversions between types. Automatic dereferencing in the " +"dot\n" +"operator is a case where the ergonomics strongly favour an implicit " +"mechanism,\n" +"but the intention is that this is limited to degrees of indirection, not\n" +"conversion between arbitrary types." +msgstr "" + +#: src\anti_patterns/deref.md:125 +msgid "" +"- [Collections are smart pointers idiom](../idioms/deref.md).\n" +"- Delegation crates for less boilerplate like [delegate](https://crates.io/" +"crates/delegate)\n" +" or [ambassador](https://crates.io/crates/ambassador)\n" +"- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" +"trait.Deref.html)." +msgstr "" + +#: src\functional/index.md:1 +msgid "# Functional Usage of Rust" +msgstr "" + +#: src\functional/index.md:3 +msgid "" +"Rust is an imperative language, but it follows many\n" +"[functional programming](https://en.wikipedia.org/wiki/" +"Functional_programming) paradigms." +msgstr "" + +#: src\functional/index.md:6 +msgid "" +"> In computer science, _functional programming_ is a programming paradigm " +"where\n" +"> programs are constructed by applying and composing functions.\n" +"> It is a declarative programming paradigm in which function definitions " +"are\n" +"> trees of expressions that each return a value, rather than a sequence of\n" +"> imperative statements which change the state of the program." +msgstr "" + +#: src\functional/paradigms.md:1 +msgid "# Programming paradigms" +msgstr "" + +#: src\functional/paradigms.md:3 +msgid "" +"One of the biggest hurdles to understanding functional programs when coming\n" +"from an imperative background is the shift in thinking. Imperative programs\n" +"describe **how** to do something, whereas declarative programs describe\n" +"**what** to do. Let's sum the numbers from 1 to 10 to show this." +msgstr "" + +#: src\functional/paradigms.md:8 +msgid "## Imperative" +msgstr "" + +#: src\functional/paradigms.md:10 +msgid "" +"```rust\n" +"let mut sum = 0;\n" +"for i in 1..11 {\n" +" sum += i;\n" +"}\n" +"println!(\"{}\", sum);\n" +"```" +msgstr "" + +#: src\functional/paradigms.md:18 +msgid "" +"With imperative programs, we have to play compiler to see what is " +"happening.\n" +"Here, we start with a `sum` of `0`.\n" +"Next, we iterate through the range from 1 to 10.\n" +"Each time through the loop, we add the corresponding value in the range.\n" +"Then we print it out." +msgstr "" + +#: src\functional/paradigms.md:24 +msgid "" +"| `i` | `sum` |\n" +"| :-: | :---: |\n" +"| 1 | 1 |\n" +"| 2 | 3 |\n" +"| 3 | 6 |\n" +"| 4 | 10 |\n" +"| 5 | 15 |\n" +"| 6 | 21 |\n" +"| 7 | 28 |\n" +"| 8 | 36 |\n" +"| 9 | 45 |\n" +"| 10 | 55 |" +msgstr "" + +#: src\functional/paradigms.md:37 +msgid "" +"This is how most of us start out programming. We learn that a program is a " +"set\n" +"of steps." +msgstr "" + +#: src\functional/paradigms.md:40 +msgid "## Declarative" +msgstr "" + +#: src\functional/paradigms.md:42 +msgid "" +"```rust\n" +"println!(\"{}\", (1..11).fold(0, |a, b| a + b));\n" +"```" +msgstr "" + +#: src\functional/paradigms.md:46 +msgid "" +"Whoa! This is really different! What's going on here?\n" +"Remember that with declarative programs we are describing **what** to do,\n" +"rather than **how** to do it. `fold` is a function that [composes](https://" +"en.wikipedia.org/wiki/Function_composition)\n" +"functions. The name is a convention from Haskell." +msgstr "" + +#: src\functional/paradigms.md:51 +msgid "" +"Here, we are composing functions of addition (this closure: `|a, b| a + b`)\n" +"with a range from 1 to 10. The `0` is the starting point, so `a` is `0` at\n" +"first. `b` is the first element of the range, `1`. `0 + 1 = 1` is the " +"result.\n" +"So now we `fold` again, with `a = 1`, `b = 2` and so `1 + 2 = 3` is the " +"next\n" +"result. This process continues until we get to the last element in the " +"range,\n" +"`10`." +msgstr "" + +#: src\functional/paradigms.md:58 +msgid "" +"| `a` | `b` | result |\n" +"| :-: | :-: | :----: |\n" +"| 0 | 1 | 1 |\n" +"| 1 | 2 | 3 |\n" +"| 3 | 3 | 6 |\n" +"| 6 | 4 | 10 |\n" +"| 10 | 5 | 15 |\n" +"| 15 | 6 | 21 |\n" +"| 21 | 7 | 28 |\n" +"| 28 | 8 | 36 |\n" +"| 36 | 9 | 45 |\n" +"| 45 | 10 | 55 |" +msgstr "" + +#: src\functional/generics-type-classes.md:1 +msgid "# Generics as Type Classes" +msgstr "" + +#: src\functional/generics-type-classes.md:5 +msgid "" +"Rust's type system is designed more like functional languages (like " +"Haskell)\n" +"rather than imperative languages (like Java and C++). As a result, Rust can " +"turn\n" +"many kinds of programming problems into \"static typing\" problems. This is " +"one\n" +"of the biggest wins of choosing a functional language, and is critical to " +"many\n" +"of Rust's compile time guarantees." +msgstr "" + +#: src\functional/generics-type-classes.md:11 +msgid "" +"A key part of this idea is the way generic types work. In C++ and Java, for\n" +"example, generic types are a meta-programming construct for the compiler.\n" +"`vector` and `vector` in C++ are just two different copies of " +"the\n" +"same boilerplate code for a `vector` type (known as a `template`) with two\n" +"different types filled in." +msgstr "" + +#: src\functional/generics-type-classes.md:17 +msgid "" +"In Rust, a generic type parameter creates what is known in functional " +"languages\n" +"as a \"type class constraint\", and each different parameter filled in by an " +"end\n" +"user _actually changes the type_. In other words, `Vec` and " +"`Vec`\n" +"_are two different types_, which are recognized as distinct by all parts of " +"the\n" +"type system." +msgstr "" + +#: src\functional/generics-type-classes.md:23 +msgid "" +"This is called **monomorphization**, where different types are created from\n" +"**polymorphic** code. This special behavior requires `impl` blocks to " +"specify\n" +"generic parameters. Different values for the generic type cause different " +"types,\n" +"and different types can have different `impl` blocks." +msgstr "" + +#: src\functional/generics-type-classes.md:28 +msgid "" +"In object-oriented languages, classes can inherit behavior from their " +"parents.\n" +"However, this allows the attachment of not only additional behavior to\n" +"particular members of a type class, but extra behavior as well." +msgstr "" + +#: src\functional/generics-type-classes.md:32 +msgid "" +"The nearest equivalent is the runtime polymorphism in Javascript and " +"Python,\n" +"where new members can be added to objects willy-nilly by any constructor.\n" +"However, unlike those languages, all of Rust's additional methods can be " +"type\n" +"checked when they are used, because their generics are statically defined. " +"That\n" +"makes them more usable while remaining safe." +msgstr "" + +#: src\functional/generics-type-classes.md:40 +msgid "" +"Suppose you are designing a storage server for a series of lab machines.\n" +"Because of the software involved, there are two different protocols you " +"need\n" +"to support: BOOTP (for PXE network boot), and NFS (for remote mount storage)." +msgstr "" + +#: src\functional/generics-type-classes.md:44 +msgid "" +"Your goal is to have one program, written in Rust, which can handle both of\n" +"them. It will have protocol handlers and listen for both kinds of requests. " +"The\n" +"main application logic will then allow a lab administrator to configure " +"storage\n" +"and security controls for the actual files." +msgstr "" + +#: src\functional/generics-type-classes.md:49 +msgid "" +"The requests from machines in the lab for files contain the same basic\n" +"information, no matter what protocol they came from: an authentication " +"method,\n" +"and a file name to retrieve. A straightforward implementation would look\n" +"something like this:" +msgstr "" + +#: src\functional/generics-type-classes.md:54 +msgid "" +"```rust,ignore\n" +"enum AuthInfo {\n" +" Nfs(crate::nfs::AuthInfo),\n" +" Bootp(crate::bootp::AuthInfo),\n" +"}\n" +"\n" +"struct FileDownloadRequest {\n" +" file_name: PathBuf,\n" +" authentication: AuthInfo,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/generics-type-classes.md:66 +msgid "" +"This design might work well enough. But now suppose you needed to support\n" +"adding metadata that was _protocol specific_. For example, with NFS, you\n" +"wanted to determine what their mount point was in order to enforce " +"additional\n" +"security rules." +msgstr "" + +#: src\functional/generics-type-classes.md:71 +msgid "" +"The way the current struct is designed leaves the protocol decision until\n" +"runtime. That means any method that applies to one protocol and not the " +"other\n" +"requires the programmer to do a runtime check." +msgstr "" + +#: src\functional/generics-type-classes.md:75 +msgid "Here is how getting an NFS mount point would look:" +msgstr "" + +#: src\functional/generics-type-classes.md:77 +msgid "" +"```rust,ignore\n" +"struct FileDownloadRequest {\n" +" file_name: PathBuf,\n" +" authentication: AuthInfo,\n" +" mount_point: Option,\n" +"}\n" +"\n" +"impl FileDownloadRequest {\n" +" // ... other methods ...\n" +"\n" +" /// Gets an NFS mount point if this is an NFS request. Otherwise,\n" +" /// return None.\n" +" pub fn mount_point(&self) -> Option<&Path> {\n" +" self.mount_point.as_ref()\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\functional/generics-type-classes.md:95 +msgid "" +"Every caller of `mount_point()` must check for `None` and write code to " +"handle\n" +"it. This is true even if they know only NFS requests are ever used in a " +"given\n" +"code path!" +msgstr "" + +#: src\functional/generics-type-classes.md:99 +msgid "" +"It would be far more optimal to cause a compile-time error if the different\n" +"request types were confused. After all, the entire path of the user's code,\n" +"including what functions from the library they use, will know whether a " +"request\n" +"is an NFS request or a BOOTP request." +msgstr "" + +#: src\functional/generics-type-classes.md:104 +msgid "" +"In Rust, this is actually possible! The solution is to _add a generic type_ " +"in\n" +"order to split the API." +msgstr "" + +#: src\functional/generics-type-classes.md:107 +msgid "Here is what that looks like:" +msgstr "" + +#: src\functional/generics-type-classes.md:109 +msgid "" +"```rust\n" +"use std::path::{Path, PathBuf};\n" +"\n" +"mod nfs {\n" +" #[derive(Clone)]\n" +" pub(crate) struct AuthInfo(String); // NFS session management omitted\n" +"}\n" +"\n" +"mod bootp {\n" +" pub(crate) struct AuthInfo(); // no authentication in bootp\n" +"}\n" +"\n" +"// private module, lest outside users invent their own protocol kinds!\n" +"mod proto_trait {\n" +" use std::path::{Path, PathBuf};\n" +" use super::{bootp, nfs};\n" +"\n" +" pub(crate) trait ProtoKind {\n" +" type AuthInfo;\n" +" fn auth_info(&self) -> Self::AuthInfo;\n" +" }\n" +"\n" +" pub struct Nfs {\n" +" auth: nfs::AuthInfo,\n" +" mount_point: PathBuf,\n" +" }\n" +"\n" +" impl Nfs {\n" +" pub(crate) fn mount_point(&self) -> &Path {\n" +" &self.mount_point\n" +" }\n" +" }\n" +"\n" +" impl ProtoKind for Nfs {\n" +" type AuthInfo = nfs::AuthInfo;\n" +" fn auth_info(&self) -> Self::AuthInfo {\n" +" self.auth.clone()\n" +" }\n" +" }\n" +"\n" +" pub struct Bootp(); // no additional metadata\n" +"\n" +" impl ProtoKind for Bootp {\n" +" type AuthInfo = bootp::AuthInfo;\n" +" fn auth_info(&self) -> Self::AuthInfo {\n" +" bootp::AuthInfo()\n" +" }\n" +" }\n" +"}\n" +"\n" +"use proto_trait::ProtoKind; // keep internal to prevent impls\n" +"pub use proto_trait::{Nfs, Bootp}; // re-export so callers can see them\n" +"\n" +"struct FileDownloadRequest {\n" +" file_name: PathBuf,\n" +" protocol: P,\n" +"}\n" +"\n" +"// all common API parts go into a generic impl block\n" +"impl FileDownloadRequest

{\n" +" fn file_path(&self) -> &Path {\n" +" &self.file_name\n" +" }\n" +"\n" +" fn auth_info(&self) -> P::AuthInfo {\n" +" self.protocol.auth_info()\n" +" }\n" +"}\n" +"\n" +"// all protocol-specific impls go into their own block\n" +"impl FileDownloadRequest {\n" +" fn mount_point(&self) -> &Path {\n" +" self.protocol.mount_point()\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" // your code here\n" +"}\n" +"```" +msgstr "" + +#: src\functional/generics-type-classes.md:190 +msgid "" +"With this approach, if the user were to make a mistake and use the wrong\n" +"type;" +msgstr "" + +#: src\functional/generics-type-classes.md:193 +msgid "" +"```rust,ignore\n" +"fn main() {\n" +" let mut socket = crate::bootp::listen()?;\n" +" while let Some(request) = socket.next_request()? {\n" +" match request.mount_point().as_ref()\n" +" \"/secure\" => socket.send(\"Access denied\"),\n" +" _ => {} // continue on...\n" +" }\n" +" // Rest of the code here\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src\functional/generics-type-classes.md:206 +msgid "" +"They would get a syntax error. The type `FileDownloadRequest` does " +"not\n" +"implement `mount_point()`, only the type `FileDownloadRequest` does. " +"And\n" +"that is created by the NFS module, not the BOOTP module of course!" +msgstr "" + +#: src\functional/generics-type-classes.md:212 +msgid "" +"First, it allows fields that are common to multiple states to be de-" +"duplicated.\n" +"By making the non-shared fields generic, they are implemented once." +msgstr "" + +#: src\functional/generics-type-classes.md:215 +msgid "" +"Second, it makes the `impl` blocks easier to read, because they are broken " +"down\n" +"by state. Methods common to all states are typed once in one block, and " +"methods\n" +"unique to one state are in a separate block." +msgstr "" + +#: src\functional/generics-type-classes.md:219 +msgid "" +"Both of these mean there are fewer lines of code, and they are better " +"organized." +msgstr "" + +#: src\functional/generics-type-classes.md:223 +msgid "" +"This currently increases the size of the binary, due to the way " +"monomorphization\n" +"is implemented in the compiler. Hopefully the implementation will be able " +"to\n" +"improve in the future." +msgstr "" + +#: src\functional/generics-type-classes.md:229 +msgid "" +"- If a type seems to need a \"split API\" due to construction or partial\n" +" initialization, consider the\n" +" [Builder Pattern](../patterns/creational/builder.md) instead.\n" +"\n" +"- If the API between types does not change -- only the behavior does -- " +"then\n" +" the [Strategy Pattern](../patterns/behavioural/strategy.md) is better " +"used\n" +" instead." +msgstr "" + +#: src\functional/generics-type-classes.md:239 +msgid "This pattern is used throughout the standard library:" +msgstr "" + +#: src\functional/generics-type-classes.md:241 +msgid "" +"- `Vec` can be cast from a String, unlike every other type of `Vec`." +"[^1]\n" +"- They can also be cast into a binary heap, but only if they contain a type\n" +" that implements the `Ord` trait.[^2]\n" +"- The `to_string` method was specialized for `Cow` only of type `str`.[^3]" +msgstr "" + +#: src\functional/generics-type-classes.md:246 +msgid "It is also used by several popular crates to allow API flexibility:" +msgstr "" + +#: src\functional/generics-type-classes.md:248 +msgid "" +"- The `embedded-hal` ecosystem used for embedded devices makes extensive use " +"of\n" +" this pattern. For example, it allows statically verifying the " +"configuration of\n" +" device registers used to control embedded pins. When a pin is put into a " +"mode,\n" +" it returns a `Pin` struct, whose generic determines the functions\n" +" usable in that mode, which are not on the `Pin` itself. [^4]\n" +"\n" +"- The `hyper` HTTP client library uses this to expose rich APIs for " +"different\n" +" pluggable requests. Clients with different connectors have different " +"methods\n" +" on them as well as different trait implementations, while a core set of\n" +" methods apply to any connector. [^5]\n" +"\n" +"- The \"type state\" pattern -- where an object gains and loses API based on " +"an\n" +" internal state or invariant -- is implemented in Rust using the same " +"basic\n" +" concept, and a slightly different technique. [^6]" +msgstr "" + +#: src\functional/generics-type-classes.md:263 +msgid "" +"See: [impl From\\ for Vec\\](https://doc.rust-lang.org/" +"1.59.0/src/std/ffi/c_str.rs.html#803-811)" +msgstr "" + +#: src\functional/generics-type-classes.md:265 +msgid "" +"See: [impl\\ From\\\\> for BinaryHeap\\]" +"(https://doc.rust-lang.org/stable/src/alloc/collections/" +"binary_heap.rs.html#1345-1354)" +msgstr "" + +#: src\functional/generics-type-classes.md:267 +msgid "" +"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, str>](https://doc.rust-" +"lang.org/stable/src/alloc/string.rs.html#2235-2240)" +msgstr "" + +#: src\functional/generics-type-classes.md:269 +msgid "" +"Example:\n" +"[https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/gpioa/" +"struct.PA0.html](https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/" +"gpioa/struct.PA0.html)" +msgstr "" + +#: src\functional/generics-type-classes.md:272 +msgid "" +"See:\n" +"[https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html](https://" +"docs.rs/hyper/0.14.5/hyper/client/struct.Client.html)" +msgstr "" + +#: src\functional/generics-type-classes.md:275 +msgid "" +"See:\n" +"[The Case for the Type State Pattern](https://web.archive.org/web/" +"20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-" +"typestate-pattern-the-typestate-pattern-itself/)\n" +"and\n" +"[Rusty Typestate Series (an extensive thesis)](https://web.archive.org/web/" +"20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/" +"rust-typestate-index)" +msgstr "" + +#: src\functional/lenses.md:1 +msgid "# Lenses and Prisms" +msgstr "" + +#: src\functional/lenses.md:3 +msgid "" +"This is a pure functional concept that is not frequently used in Rust.\n" +"Nevertheless, exploring the concept may be helpful to understand other\n" +"patterns in Rust APIs, such as [visitors](../patterns/behavioural/" +"visitor.md).\n" +"They also have niche use cases." +msgstr "" + +#: src\functional/lenses.md:8 +msgid "## Lenses: Uniform Access Across Types" +msgstr "" + +#: src\functional/lenses.md:10 +msgid "" +"A lens is a concept from functional programming languages that allows\n" +"accessing parts of a data type in an abstract, unified way.[^1]\n" +"In basic concept, it is similar to the way Rust traits work with type " +"erasure,\n" +"but it has a bit more power and flexibility." +msgstr "" + +#: src\functional/lenses.md:15 +msgid "" +"For example, suppose a bank contains several JSON formats for customer\n" +"data.\n" +"This is because they come from different databases or legacy systems.\n" +"One database contains the data needed to perform credit checks:" +msgstr "" + +#: src\functional/lenses.md:20 +msgid "" +"```json\n" +"{ \"name\": \"Jane Doe\",\n" +" \"dob\": \"2002-02-24\",\n" +" [...]\n" +" \"customer_id\": 1048576332,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:28 +msgid "Another one contains the account information:" +msgstr "" + +#: src\functional/lenses.md:30 +msgid "" +"```json\n" +"{ \"customer_id\": 1048576332,\n" +" \"accounts\": [\n" +" { \"account_id\": 2121,\n" +" \"account_type: \"savings\",\n" +" \"joint_customer_ids\": [],\n" +" [...]\n" +" },\n" +" { \"account_id\": 2122,\n" +" \"account_type: \"checking\",\n" +" \"joint_customer_ids\": [1048576333],\n" +" [...]\n" +" },\n" +" ]\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:47 +msgid "" +"Notice that both types have a customer ID number which corresponds to a " +"person.\n" +"How would a single function handle both records of different types?" +msgstr "" + +#: src\functional/lenses.md:50 +msgid "" +"In Rust, a `struct` could represent each of these types, and a trait would " +"have\n" +"a `get_customer_id` function they would implement:" +msgstr "" + +#: src\functional/lenses.md:53 +msgid "" +"```rust\n" +"use std::collections::HashSet;\n" +"\n" +"pub struct Account {\n" +" account_id: u32,\n" +" account_type: String,\n" +" // other fields omitted\n" +"}\n" +"\n" +"pub trait CustomerId {\n" +" fn get_customer_id(&self) -> u64;\n" +"}\n" +"\n" +"pub struct CreditRecord {\n" +" customer_id: u64,\n" +" name: String,\n" +" dob: String,\n" +" // other fields omitted\n" +"}\n" +"\n" +"impl CustomerId for CreditRecord {\n" +" fn get_customer_id(&self) -> u64 {\n" +" self.customer_id\n" +" }\n" +"}\n" +"\n" +"pub struct AccountRecord {\n" +" customer_id: u64,\n" +" accounts: Vec,\n" +"}\n" +"\n" +"impl CustomerId for AccountRecord {\n" +" fn get_customer_id(&self) -> u64 {\n" +" self.customer_id\n" +" }\n" +"}\n" +"\n" +"// static polymorphism: only one type, but each function call can choose it\n" +"fn unique_ids_set(records: &[R]) -> HashSet {\n" +" records.iter().map(|r| r.get_customer_id()).collect()\n" +"}\n" +"\n" +"// dynamic dispatch: iterates over any type with a customer ID, collecting " +"all\n" +"// values together\n" +"fn unique_ids_iter(iterator: I) -> HashSet\n" +" where I: Iterator>\n" +"{\n" +" iterator.map(|r| r.as_ref().get_customer_id()).collect()\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:104 +msgid "" +"Lenses, however, allow the code supporting customer ID to be moved from the\n" +"_type_ to the _accessor function_.\n" +"Rather than implementing a trait on each type, all matching structures can\n" +"simply be accessed the same way." +msgstr "" + +#: src\functional/lenses.md:109 +msgid "" +"While the Rust language itself does not support this (type erasure is the\n" +"preferred solution to this problem), the [lens-rs crate](https://github.com/" +"TOETOE55/lens-rs/blob/master/guide.md) allows code\n" +"that feels like this to be written with macros:" +msgstr "" + +#: src\functional/lenses.md:113 +msgid "" +"```rust,ignore\n" +"use std::collections::HashSet;\n" +"\n" +"use lens_rs::{optics, Lens, LensRef, Optics};\n" +"\n" +"#[derive(Clone, Debug, Lens /* derive to allow lenses to work */)]\n" +"pub struct CreditRecord {\n" +" #[optic(ref)] // macro attribute to allow viewing this field\n" +" customer_id: u64,\n" +" name: String,\n" +" dob: String,\n" +" // other fields omitted\n" +"}\n" +"\n" +"#[derive(Clone, Debug)]\n" +"pub struct Account {\n" +" account_id: u32,\n" +" account_type: String,\n" +" // other fields omitted\n" +"}\n" +"\n" +"#[derive(Clone, Debug, Lens)]\n" +"pub struct AccountRecord {\n" +" #[optic(ref)]\n" +" customer_id: u64,\n" +" accounts: Vec,\n" +"}\n" +"\n" +"fn unique_ids_lens(iter: impl Iterator) -> HashSet\n" +"where\n" +" T: LensRef, // any type with this field\n" +"{\n" +" iter.map(|r| *r.view_ref(optics!(customer_id))).collect()\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:149 +msgid "" +"The version of `unique_ids_lens` shown here allows any type to be in the " +"iterator,\n" +"so long as it has an attribute called `customer_id` which can be accessed " +"by\n" +"the function.\n" +"This is how most functional programming languages operate on lenses." +msgstr "" + +#: src\functional/lenses.md:154 +msgid "" +"Rather than macros, they achieve this with a technique known as " +"\"currying\".\n" +"That is, they \"partially construct\" the function, leaving the type of the\n" +"final parameter (the value being operated on) unfilled until the function " +"is\n" +"called.\n" +"Thus it can be called with different types dynamically even from one place " +"in\n" +"the code.\n" +"That is what the `optics!` and `view_ref` in the example above simulates." +msgstr "" + +#: src\functional/lenses.md:162 +msgid "" +"The functional approach need not be restricted to accessing members.\n" +"More powerful lenses can be created which both _set_ and _get_ data in a\n" +"structure.\n" +"But the concept really becomes interesting when used as a building block " +"for\n" +"composition.\n" +"That is where the concept appears more clearly in Rust." +msgstr "" + +#: src\functional/lenses.md:169 +msgid "## Prisms: A Higher-Order form of \"Optics\"" +msgstr "" + +#: src\functional/lenses.md:171 +msgid "" +"A simple function such as `unique_ids_lens` above operates on a single " +"lens.\n" +"A _prism_ is a function that operates on a _family_ of lenses.\n" +"It is one conceptual level higher, using lenses as a building block, and\n" +"continuing the metaphor, is part of a family of \"optics\".\n" +"It is the main one that is useful in understanding Rust APIs, so will be " +"the\n" +"focus here." +msgstr "" + +#: src\functional/lenses.md:178 +msgid "" +"The same way that traits allow \"lens-like\" design with static polymorphism " +"and\n" +"dynamic dispatch, prism-like designs appear in Rust APIs which split " +"problems\n" +"into multiple associated types to be composed.\n" +"A good example of this is the traits in the parsing crate _Serde_." +msgstr "" + +#: src\functional/lenses.md:183 +msgid "" +"Trying to understand the way _Serde_ works by only reading the API is a\n" +"challenge, especially the first time.\n" +"Consider the `Deserializer` trait, implemented by some type in any library\n" +"which parses a new format:" +msgstr "" + +#: src\functional/lenses.md:188 +msgid "" +"```rust,ignore\n" +"pub trait Deserializer<'de>: Sized {\n" +" type Error: Error;\n" +"\n" +" fn deserialize_any(self, visitor: V) -> Result\n" +" where\n" +" V: Visitor<'de>;\n" +"\n" +" fn deserialize_bool(self, visitor: V) -> Result\n" +" where\n" +" V: Visitor<'de>;\n" +"\n" +" // remainder ommitted\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:204 +msgid "" +"For a trait that is just supposed to parse data from a format and return a\n" +"value, this looks odd." +msgstr "" + +#: src\functional/lenses.md:207 +msgid "Why are all the return types type erased?" +msgstr "" + +#: src\functional/lenses.md:209 +msgid "" +"To understand that, we need to keep the lens concept in mind and look at\n" +"the definition of the `Visitor` type that is passed in generically:" +msgstr "" + +#: src\functional/lenses.md:212 +msgid "" +"```rust,ignore\n" +"pub trait Visitor<'de>: Sized {\n" +" type Value;\n" +"\n" +" fn visit_bool(self, v: bool) -> Result\n" +" where\n" +" E: Error;\n" +"\n" +" fn visit_u64(self, v: u64) -> Result\n" +" where\n" +" E: Error;\n" +"\n" +" fn visit_str(self, v: &str) -> Result\n" +" where\n" +" E: Error;\n" +"\n" +" // remainder omitted\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:232 +msgid "" +"The job of the `Visitor` type is to construct values in the _Serde_ data " +"model,\n" +"which are represented by its associated `Value` type." +msgstr "" + +#: src\functional/lenses.md:235 +msgid "" +"These values represent parts of the Rust value being deserialized.\n" +"If this fails, it returns an `Error` type - an error type determined by the\n" +"`Deserializer` when its methods were called." +msgstr "" + +#: src\functional/lenses.md:239 +msgid "" +"This highlights that `Deserializer` is similar to `CustomerId` from " +"earlier,\n" +"allowing any format parser which implements it to create `Value`s based on " +"what\n" +"it parsed.\n" +"The `Value` trait is acting like a lens in functional programming languages." +msgstr "" + +#: src\functional/lenses.md:244 +msgid "" +"But unlike the `CustomerId` trait, the return types of `Visitor` methods " +"are\n" +"_generic_, and the concrete `Value` type is _determined by the Visitor " +"itself_." +msgstr "" + +#: src\functional/lenses.md:247 +msgid "" +"Instead of acting as one lens, it effectively acts as a family of\n" +"lenses, one for each concrete type of `Visitor`." +msgstr "" + +#: src\functional/lenses.md:250 +msgid "" +"The `Deserializer` API is based on having a generic set of \"lenses\" work " +"across\n" +"a set of other generic types for \"observation\".\n" +"It is a _prism_." +msgstr "" + +#: src\functional/lenses.md:254 +msgid "For example, consider the identity record from earlier but simplified:" +msgstr "" + +#: src\functional/lenses.md:256 +msgid "" +"```json\n" +"{ \"name\": \"Jane Doe\",\n" +" \"customer_id\": 1048576332,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:262 +msgid "" +"How would the _Serde_ library deserialize this JSON into `struct " +"CreditRecord`?" +msgstr "" + +#: src\functional/lenses.md:264 +msgid "" +"1. The user would call a library function to deserialize the data. This " +"would\n" +" create a `Deserializer` based on the JSON format.\n" +"1. Based on the fields in the struct, a `Visitor` would be created (more on\n" +" that in a moment) which knows how to create each type in a generic data\n" +" model that was needed to represent it: `u64` and `String`.\n" +"1. The deserializer would make calls to the `Visitor` as it parsed items.\n" +"1. The `Visitor` would indicate if the items found were expected, and if " +"not,\n" +" raise an error to indicate deserialization has failed." +msgstr "" + +#: src\functional/lenses.md:273 +msgid "For our very simple structure above, the expected pattern would be:" +msgstr "" + +#: src\functional/lenses.md:275 +msgid "" +"1. Visit a map (_Serde_'s equvialent to `HashMap` or JSON's dictionary).\n" +"1. Visit a string key called \"name\".\n" +"1. Visit a string value, which will go into the `name` field.\n" +"1. Visit a string key called \"customer_id\".\n" +"1. Visit a string value, which will go into the `customer_id` field.\n" +"1. Visit the end of the map." +msgstr "" + +#: src\functional/lenses.md:282 +msgid "But what determines which \"observation\" pattern is expected?" +msgstr "" + +#: src\functional/lenses.md:284 +msgid "" +"A functional programming language would be able to use currying to create\n" +"reflection of each type based on the type itself.\n" +"Rust does not support that, so every single type would need to have its own\n" +"code written based on its fields and their properties." +msgstr "" + +#: src\functional/lenses.md:289 +msgid "_Serde_ solves this usability challenge with a derive macro:" +msgstr "" + +#: src\functional/lenses.md:291 +msgid "" +"```rust,ignore\n" +"use serde::Deserialize;\n" +"\n" +"#[derive(Deserialize)]\n" +"struct IdRecord {\n" +" name: String,\n" +" customer_id: String,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:301 +msgid "" +"That macro simply generates an impl block causing the struct to implement a\n" +"trait called `Deserialize`." +msgstr "" + +#: src\functional/lenses.md:304 +msgid "It is defined this way:" +msgstr "" + +#: src\functional/lenses.md:306 +msgid "" +"```rust,ignore\n" +"pub trait Deserialize<'de>: Sized {\n" +" fn deserialize(deserializer: D) -> Result\n" +" where\n" +" D: Deserializer<'de>;\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:314 +msgid "" +"This is the function that determines how to create the struct itself.\n" +"Code is generated based on the struct's fields.\n" +"When the parsing library is called - in our example, a JSON parsing library " +"-\n" +"it creates a `Deserializer` and calls `Type::deserialize` with it as a\n" +"parameter." +msgstr "" + +#: src\functional/lenses.md:320 +msgid "" +"The `deserialize` code will then create a `Visitor` which will have its " +"calls\n" +"\"refracted\" by the `Deserializer`.\n" +"If everything goes well, eventually that `Visitor` will construct a value\n" +"corresponding to the type being parsed and return it." +msgstr "" + +#: src\functional/lenses.md:325 +msgid "" +"For a complete example, see the [_Serde_ documentation](https://serde.rs/" +"deserialize-struct.html)." +msgstr "" + +#: src\functional/lenses.md:327 +msgid "To wrap up, this is the power of _Serde_:" +msgstr "" + +#: src\functional/lenses.md:329 +msgid "" +"1. The structure being parsed is represented by an `impl` block for " +"`Deserialize`\n" +"1. The input data format (e.g. JSON) is represented by a `Deserializer` " +"called\n" +" by `Deserialize`\n" +"1. The `Deserializer` acts like a prism which \"refracts\" lens-like " +"`Visitor`\n" +" calls which actually build the data value" +msgstr "" + +#: src\functional/lenses.md:335 +msgid "" +"The result is that types to be deserialized only implement the \"top layer\" " +"of\n" +"the API, and file formats only need to implement the \"bottom layer\".\n" +"Each piece can then \"just work\" with the rest of the ecosystem, since " +"generic\n" +"types will bridge them." +msgstr "" + +#: src\functional/lenses.md:340 +msgid "" +"To emphasize, the only reason this model works on any format and any type " +"is\n" +"because the `Deserializer` trait's output type **is specified by the\n" +"implementor of `Visitor` it is passed**, rather than being tied to one " +"specific\n" +"type.\n" +"This was not true in the account example earlier." +msgstr "" + +#: src\functional/lenses.md:346 +msgid "" +"Rust's generic-inspired type system can bring it close to these concepts " +"and\n" +"use their power, as shown in this API design.\n" +"But it may also need procedural macros to create bridges for its generics." +msgstr "" + +#: src\functional/lenses.md:350 +msgid "## See Also" +msgstr "" + +#: src\functional/lenses.md:352 +msgid "" +"- [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses\n" +" implementation, with a cleaner interface than these examples\n" +"- [serde](https://serde.rs) itself, which makes these concepts intuitive " +"for\n" +" end users (i.e. defining the structs) without needing to undestand the\n" +" details\n" +"- [luminance](https://github.com/phaazon/luminance-rs) is a crate for " +"drawing\n" +" computer graphics that uses lens API design, including proceducal macros " +"to\n" +" create full prisms for buffers of different pixel types that remain " +"generic\n" +"- [An Article about Lenses in Scala](https://web.archive.org/web/" +"20221128185849/https://medium.com/zyseme-technology/functional-references-" +"lens-and-other-optics-in-scala-e5f7e2fdafe)\n" +" that is very readable even without Scala expertise.\n" +"- [Paper: Profunctor Optics: Modular Data\n" +" Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/" +"ftp/arxiv/papers/1703/1703.10857.pdf)" +msgstr "" + +#: src\functional/lenses.md:365 +msgid "" +"[School of Haskell: A Little Lens Starter Tutorial](https://web.archive.org/" +"web/20221128190041/https://www.schoolofhaskell.com/school/to-infinity-and-" +"beyond/pick-of-the-week/a-little-lens-starter-tutorial)" +msgstr "" + +#: src\additional_resources/index.md:1 +msgid "# Additional resources" +msgstr "" + +#: src\additional_resources/index.md:3 +msgid "A collection of complementary helpful content" +msgstr "" + +#: src\additional_resources/index.md:5 +msgid "## Talks" +msgstr "" + +#: src\additional_resources/index.md:7 +msgid "" +"- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by\n" +" Nicholas Cameron at the PDRust (2016)\n" +"- [Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?" +"v=0zOg8_B71gE)\n" +" by Pascal Hertleif at RustFest (2017)\n" +"- [Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) " +"by\n" +" Nicholas Cameron at LinuxConfAu (2018)" +msgstr "" + +#: src\additional_resources/index.md:14 +msgid "## Books (Online)" +msgstr "" + +#: src\additional_resources/index.md:16 +msgid "- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" +msgstr "" + +#: src\additional_resources/design-principles.md:1 +msgid "# Design principles" +msgstr "" + +#: src\additional_resources/design-principles.md:3 +msgid "## A brief overview over common design principles" +msgstr "" + +#: src\additional_resources/design-principles.md:7 +msgid "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" +msgstr "" + +#: src\additional_resources/design-principles.md:9 +msgid "" +"- [Single Responsibility Principle (SRP)](https://en.wikipedia.org/wiki/" +"Single-responsibility_principle):\n" +" A class should only have a single responsibility, that is, only changes " +"to\n" +" one part of the software's specification should be able to affect the\n" +" specification of the class.\n" +"- [Open/Closed Principle (OCP)](https://en.wikipedia.org/wiki/" +"Open%E2%80%93closed_principle):\n" +" \"Software entities ... should be open for extension, but closed for\n" +" modification.\"\n" +"- [Liskov Substitution Principle (LSP)](https://en.wikipedia.org/wiki/" +"Liskov_substitution_principle):\n" +" \"Objects in a program should be replaceable with instances of their " +"subtypes\n" +" without altering the correctness of that program.\"\n" +"- [Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/" +"Interface_segregation_principle):\n" +" \"Many client-specific interfaces are better than one general-purpose\n" +" interface.\"\n" +"- [Dependency Inversion Principle (DIP)](https://en.wikipedia.org/wiki/" +"Dependency_inversion_principle):\n" +" One should \"depend upon abstractions, [not] concretions.\"" +msgstr "" + +#: src\additional_resources/design-principles.md:25 +msgid "" +"## [DRY (Don’t Repeat Yourself)](https://en.wikipedia.org/wiki/" +"Don%27t_repeat_yourself)" +msgstr "" + +#: src\additional_resources/design-principles.md:27 +msgid "" +"\"Every piece of knowledge must have a single, unambiguous, authoritative\n" +"representation within a system\"" +msgstr "" + +#: src\additional_resources/design-principles.md:30 +msgid "## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" +msgstr "" + +#: src\additional_resources/design-principles.md:32 +msgid "" +"most systems work best if they are kept simple rather than made " +"complicated;\n" +"therefore, simplicity should be a key goal in design, and unnecessary\n" +"complexity should be avoided" +msgstr "" + +#: src\additional_resources/design-principles.md:36 +msgid "## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" +msgstr "" + +#: src\additional_resources/design-principles.md:38 +msgid "" +"a given object should assume as little as possible about the structure or\n" +"properties of anything else (including its subcomponents), in accordance " +"with\n" +"the principle of \"information hiding\"" +msgstr "" + +#: src\additional_resources/design-principles.md:42 +msgid "" +"## [Design by contract (DbC)](https://en.wikipedia.org/wiki/" +"Design_by_contract)" +msgstr "" + +#: src\additional_resources/design-principles.md:44 +msgid "" +"software designers should define formal, precise and verifiable interface\n" +"specifications for software components, which extend the ordinary definition " +"of\n" +"abstract data types with preconditions, postconditions and invariants" +msgstr "" + +#: src\additional_resources/design-principles.md:48 +msgid "" +"## [Encapsulation](https://en.wikipedia.org/wiki/" +"Encapsulation_(computer_programming))" +msgstr "" + +#: src\additional_resources/design-principles.md:50 +msgid "" +"bundling of data with the methods that operate on that data, or the " +"restricting\n" +"of direct access to some of an object's components. Encapsulation is used " +"to\n" +"hide the values or state of a structured data object inside a class, " +"preventing\n" +"unauthorized parties' direct access to them." +msgstr "" + +#: src\additional_resources/design-principles.md:55 +msgid "" +"## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/" +"Command%E2%80%93query_separation)" +msgstr "" + +#: src\additional_resources/design-principles.md:57 +msgid "" +"“Functions should not produce abstract side effects...only commands\n" +"(procedures) will be permitted to produce side effects.” - Bertrand Meyer:\n" +"Object-Oriented Software Construction" +msgstr "" + +#: src\additional_resources/design-principles.md:61 +msgid "" +"## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/" +"Principle_of_least_astonishment)" +msgstr "" + +#: src\additional_resources/design-principles.md:63 +msgid "" +"a component of a system should behave in a way that most users will expect " +"it\n" +"to behave. The behavior should not astonish or surprise users" +msgstr "" + +#: src\additional_resources/design-principles.md:66 +msgid "## Linguistic-Modular-Units" +msgstr "" + +#: src\additional_resources/design-principles.md:68 +msgid "" +"“Modules must correspond to syntactic units in the language used.” - " +"Bertrand\n" +"Meyer: Object-Oriented Software Construction" +msgstr "" + +#: src\additional_resources/design-principles.md:71 +msgid "## Self-Documentation" +msgstr "" + +#: src\additional_resources/design-principles.md:73 +msgid "" +"“The designer of a module should strive to make all information about the\n" +"module part of the module itself.” - Bertrand Meyer: Object-Oriented " +"Software\n" +"Construction" +msgstr "" + +#: src\additional_resources/design-principles.md:77 +msgid "## Uniform-Access" +msgstr "" + +#: src\additional_resources/design-principles.md:79 +msgid "" +"“All services offered by a module should be available through a uniform\n" +"notation, which does not betray whether they are implemented through storage " +"or\n" +"through computation.” - Bertrand Meyer: Object-Oriented Software Construction" +msgstr "" + +#: src\additional_resources/design-principles.md:83 +msgid "## Single-Choice" +msgstr "" + +#: src\additional_resources/design-principles.md:85 +msgid "" +"“Whenever a software system must support a set of alternatives, one and " +"only\n" +"one module in the system should know their exhaustive list.” - Bertrand " +"Meyer:\n" +"Object-Oriented Software Construction" +msgstr "" + +#: src\additional_resources/design-principles.md:89 +msgid "## Persistence-Closure" +msgstr "" + +#: src\additional_resources/design-principles.md:91 +msgid "" +"“Whenever a storage mechanism stores an object, it must store with it the\n" +"dependents of that object. Whenever a retrieval mechanism retrieves a\n" +"previously stored object, it must also retrieve any dependent of that " +"object\n" +"that has not yet been retrieved.” - Bertrand Meyer: Object-Oriented " +"Software\n" +"Construction" +msgstr "" From a2f6947335041b1effe11bcf9d5353981fd0608b Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Sat, 17 May 2025 14:55:05 +0900 Subject: [PATCH 02/12] Japanese translation: Introduction --- po/ja.po | 9130 +++++++++++++++++++++++------------------------------- 1 file changed, 3954 insertions(+), 5176 deletions(-) diff --git a/po/ja.po b/po/ja.po index 46474640..b66262f7 100644 --- a/po/ja.po +++ b/po/ja.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" -"POT-Creation-Date: \n" -"PO-Revision-Date: 2025-05-17 14:04+0900\n" +"POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" +"PO-Revision-Date: 2025-05-17 14:53+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -12,209 +12,209 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.6\n" -#: src\SUMMARY.md:3 +#: src/SUMMARY.md:1 +msgid "Summary" +msgstr "概要" + +#: src/SUMMARY.md:3 src/intro.md:1 msgid "Introduction" msgstr "序文" -#: src\SUMMARY.md:4 +#: src/SUMMARY.md:4 src/translations.md:1 msgid "Translations" msgstr "翻訳" -#: src\SUMMARY.md:5 +#: src/SUMMARY.md:5 src/idioms/index.md:1 msgid "Idioms" msgstr "慣習" -#: src\SUMMARY.md:6 +#: src/SUMMARY.md:6 src/idioms/coercion-arguments.md:1 msgid "Use borrowed types for arguments" msgstr "引数には借用型を使う" -#: src\SUMMARY.md:7 +#: src/SUMMARY.md:7 msgid "Concatenating Strings with format!" msgstr "format! による文字列連結" -#: src\SUMMARY.md:8 +#: src/SUMMARY.md:8 msgid "Constructor" msgstr "コンストラクタ" -#: src\SUMMARY.md:9 +#: src/SUMMARY.md:9 msgid "The Default Trait" msgstr "Defaultトレイトの活用" -#: src\SUMMARY.md:10 +#: src/SUMMARY.md:10 msgid "Collections Are Smart Pointers" msgstr "コレクションはスマートポインタである" -#: src\SUMMARY.md:11 +#: src/SUMMARY.md:11 msgid "Finalisation in Destructors" msgstr "デストラクタでの後処理" -#: src\SUMMARY.md:12 -msgid "mem::{take(_), replace(_)}" -msgstr "mem::{take(_), replace(_)}" +#: src/SUMMARY.md:12 +msgid "`mem::{take(_), replace(_)}`" +msgstr "" -#: src\SUMMARY.md:13 +#: src/SUMMARY.md:13 src/idioms/on-stack-dyn-dispatch.md:1 msgid "On-Stack Dynamic Dispatch" msgstr "スタック上での動的ディスパッチ" -#: src\SUMMARY.md:14 src\SUMMARY.md:40 +#: src/SUMMARY.md:14 src/SUMMARY.md:40 msgid "Foreign function interface (FFI)" msgstr "外部関数インターフェース(FFI)" -#: src\SUMMARY.md:15 +#: src/SUMMARY.md:15 msgid "Idiomatic Errors" msgstr "FFIに適したエラー処理" -#: src\SUMMARY.md:16 +#: src/SUMMARY.md:16 src/idioms/ffi/accepting-strings.md:1 msgid "Accepting Strings" msgstr "文字列の受け取り方" -#: src\SUMMARY.md:17 +#: src/SUMMARY.md:17 src/idioms/ffi/passing-strings.md:1 msgid "Passing Strings" msgstr "文字列の渡し方" -#: src\SUMMARY.md:18 +#: src/SUMMARY.md:18 msgid "Iterating over an Option" msgstr "Optionをイテレータとして使う" -#: src\SUMMARY.md:19 +#: src/SUMMARY.md:19 msgid "Pass Variables to Closure" msgstr "クロージャの変数キャプチャ" -#: src\SUMMARY.md:20 +#: src/SUMMARY.md:20 msgid "Privacy For Extensibility" msgstr "拡張性のためのプライバシー制御" -#: src\SUMMARY.md:21 +#: src/SUMMARY.md:21 src/idioms/rustdoc-init.md:1 msgid "Easy doc initialization" msgstr "ドキュメント用の初期化の簡素化" -#: src\SUMMARY.md:22 +#: src/SUMMARY.md:22 src/idioms/temporary-mutability.md:1 msgid "Temporary mutability" msgstr "一時的な可変性" -#: src\SUMMARY.md:23 +#: src/SUMMARY.md:23 msgid "Return consumed arg on error" msgstr "消費した引数をエラー時に返す" -#: src\SUMMARY.md:25 +#: src/SUMMARY.md:25 src/patterns/index.md:1 msgid "Design Patterns" msgstr "" -#: src\SUMMARY.md:26 +#: src/SUMMARY.md:26 msgid "Behavioural" msgstr "" -#: src\SUMMARY.md:27 +#: src/SUMMARY.md:27 src/patterns/behavioural/command.md:1 msgid "Command" msgstr "" -#: src\SUMMARY.md:28 +#: src/SUMMARY.md:28 src/patterns/behavioural/interpreter.md:1 msgid "Interpreter" msgstr "" -#: src\SUMMARY.md:29 +#: src/SUMMARY.md:29 src/patterns/behavioural/newtype.md:1 msgid "Newtype" msgstr "" -#: src\SUMMARY.md:30 +#: src/SUMMARY.md:30 msgid "RAII Guards" msgstr "" -#: src\SUMMARY.md:31 +#: src/SUMMARY.md:31 msgid "Strategy" msgstr "" -#: src\SUMMARY.md:32 +#: src/SUMMARY.md:32 src/patterns/behavioural/visitor.md:1 msgid "Visitor" msgstr "" -#: src\SUMMARY.md:33 +#: src/SUMMARY.md:33 msgid "Creational" msgstr "" -#: src\SUMMARY.md:34 +#: src/SUMMARY.md:34 src/patterns/creational/builder.md:1 msgid "Builder" msgstr "" -#: src\SUMMARY.md:35 +#: src/SUMMARY.md:35 src/patterns/creational/fold.md:1 msgid "Fold" msgstr "" -#: src\SUMMARY.md:36 +#: src/SUMMARY.md:36 msgid "Structural" msgstr "" -#: src\SUMMARY.md:37 +#: src/SUMMARY.md:37 msgid "Compose Structs" msgstr "" -#: src\SUMMARY.md:38 +#: src/SUMMARY.md:38 msgid "Prefer Small Crates" msgstr "" -#: src\SUMMARY.md:39 +#: src/SUMMARY.md:39 src/patterns/structural/unsafe-mods.md:1 msgid "Contain unsafety in small modules" msgstr "" -#: src\SUMMARY.md:41 +#: src/SUMMARY.md:41 src/patterns/ffi/export.md:1 msgid "Object-Based APIs" msgstr "" -#: src\SUMMARY.md:42 +#: src/SUMMARY.md:42 src/patterns/ffi/wrappers.md:1 msgid "Type Consolidation into Wrappers" msgstr "" -#: src\SUMMARY.md:44 +#: src/SUMMARY.md:44 src/anti_patterns/index.md:1 msgid "Anti-patterns" msgstr "" -#: src\SUMMARY.md:45 +#: src/SUMMARY.md:45 src/anti_patterns/borrow_clone.md:1 msgid "Clone to satisfy the borrow checker" msgstr "" -#: src\SUMMARY.md:46 -msgid "#[deny(warnings)]" +#: src/SUMMARY.md:46 +msgid "`#[deny(warnings)]`" msgstr "" -#: src\SUMMARY.md:47 +#: src/SUMMARY.md:47 msgid "Deref Polymorphism" msgstr "" -#: src\SUMMARY.md:49 +#: src/SUMMARY.md:49 msgid "Functional Programming" msgstr "" -#: src\SUMMARY.md:50 +#: src/SUMMARY.md:50 src/functional/paradigms.md:1 msgid "Programming paradigms" msgstr "" -#: src\SUMMARY.md:51 +#: src/SUMMARY.md:51 src/functional/generics-type-classes.md:1 msgid "Generics as Type Classes" msgstr "" -#: src\SUMMARY.md:52 -msgid "Lenses and Prisms" +#: src/SUMMARY.md:52 +msgid "Functional Optics" msgstr "" -#: src\SUMMARY.md:54 +#: src/SUMMARY.md:54 msgid "Additional Resources" msgstr "" -#: src\SUMMARY.md:55 +#: src/SUMMARY.md:55 src/additional_resources/design-principles.md:1 msgid "Design principles" msgstr "" -#: src\intro.md:1 -msgid "# Introduction" -msgstr "" - -#: src\intro.md:3 -msgid "## Participation" +#: src/intro.md:3 +msgid "Participation" msgstr "参加する" -#: src\intro.md:5 +#: src/intro.md:5 msgid "" -"If you are interested in contributing to this book, check out the\n" +"If you are interested in contributing to this book, check out the " "[contribution guidelines](https://github.com/rust-unofficial/patterns/blob/" "master/CONTRIBUTING.md)." msgstr "" @@ -222,1521 +222,1333 @@ msgstr "" "(https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md)をご" "覧ください。" -#: src\intro.md:8 -msgid "## Design patterns" +#: src/intro.md:8 +msgid "News" +msgstr "ニュース" + +#: src/intro.md:10 +msgid "" +"**2024-03-17**: You can now download the book in PDF format from [this link]" +"(https://rust-unofficial.github.io/patterns/rust-design-patterns.pdf)." msgstr "" +"**2024-03-17**: [このリンク](https://rust-unofficial.github.io/patterns/rust-" +"design-patterns.pdf)からPDF形式でダウンロードできます。" -#: src\intro.md:10 +#: src/intro.md:13 +msgid "Design patterns" +msgstr "デザインパターン" + +#: src/intro.md:15 msgid "" -"In software development, we often come across problems that share\n" -"similarities regardless of the environment they appear in. Although the\n" -"implementation details are crucial to solve the task at hand, we may\n" -"abstract from these particularities to find the common practices that\n" -"are generically applicable." +"In software development, we often come across problems that share " +"similarities regardless of the environment they appear in. Although the " +"implementation details are crucial to solve the task at hand, we may " +"abstract from these particularities to find the common practices that are " +"generically applicable." msgstr "" +"ソフトウェア開発では、どんな環境であってもよく似た問題に出くわすことがありま" +"す。その場その場での具体的な実装はもちろん大切ですが、そうした個別の事情から" +"一歩引いて、より汎用的に使える共通のやり方を見つけることもできます。" -#: src\intro.md:16 +#: src/intro.md:20 msgid "" -"Design patterns are a collection of reusable and tested solutions to\n" -"recurring problems in engineering. They make our software more modular,\n" -"maintainable, and extensible. Moreover, these patterns provide a common\n" -"language for developers, making them an excellent tool for effective\n" +"Design patterns are a collection of reusable and tested solutions to " +"recurring problems in engineering. They make our software more modular, " +"maintainable, and extensible. Moreover, these patterns provide a common " +"language for developers, making them an excellent tool for effective " "communication when problem-solving in teams." msgstr "" +"デザインパターンとは、こうした繰り返し登場する課題に対して、再利用可能かつテ" +"スト済みの解決策をまとめたものです。これらを使うことで、ソフトウェアの構造は" +"よりモジュール化され、保守しやすく、拡張しやすくなります。さらに、パターンは" +"開発者同士の共通言語にもなり、チームで問題を解決するときのコミュニケーション" +"手段としても非常に役立ちます。" + +#: src/intro.md:26 +msgid "" +"Keep in mind: Each pattern comes with its own set of trade-offs. It's " +"crucial to focus on why you choose a particular pattern rather than just on " +"how to implement it.[^1]" +msgstr "" +"ただし注意が必要です。どのパターンにも必ずトレードオフがあります。実装方法に" +"気を取られるのではなく、「なぜそのパターンを選ぶのか」という目的にこそ意識を" +"向けましょう。[^1]" + +#: src/intro.md:30 src/patterns/index.md:14 +msgid "Design patterns in Rust" +msgstr "Rustにおけるデザインパターン" + +#: src/intro.md:32 +msgid "" +"Rust is not object-oriented, and the combination of all its characteristics, " +"such as functional elements, a strong type system, and the borrow checker, " +"makes it unique. Because of this, Rust design patterns vary with respect to " +"other traditional object-oriented programming languages. That's why we " +"decided to write this book. We hope you enjoy reading it! The book is " +"divided in three main chapters:" +msgstr "" +"Rustはオブジェクト指向の言語ではありません。\n" +"関数型の要素、強力な型システム、そして借用チェッカーといった特徴が組み合わさ" +"ることで、Rustは他の言語とは一線を画す存在となっています。\n" +"\n" +"そのため、Rustにおけるデザインパターンは、従来のオブジェクト指向言語とは異な" +"る形になります。\n" +"私たちがこの本を書こうと決めたのも、まさにその理由からです。\n" +"Rustらしい設計や書き方を体系的に学ぶための手引きとして、楽しんで読んでいただ" +"ければ幸いです。\n" +"\n" +"本書は次の3つの大きな章に分かれています:" -#: src\intro.md:22 src\patterns/index.md:14 -msgid "## Design patterns in Rust" +#: src/intro.md:39 +msgid "" +"[Idioms](./idioms/index.md): guidelines to follow when coding. They are the " +"social norms of the community. You should break them only if you have a good " +"reason for it." msgstr "" +"[慣習](./idioms/index.md): コーディングにおいて推奨される書き方。コミュニティ" +"内の社会的規範。慣習は破っても構いませんが、きちんと理由がある場合に限りま" +"す。" -#: src\intro.md:24 +#: src/intro.md:42 msgid "" -"Rust is not object-oriented, and the combination of all its " -"characteristics,\n" -"such as functional elements, a strong type system, and the borrow checker,\n" -"makes it unique.\n" -"Because of this, Rust design patterns vary with respect to other\n" -"traditional object-oriented programming languages.\n" -"That's why we decided to write this book. We hope you enjoy reading it!\n" -"The book is divided in three main chapters:" +"[Design patterns](./patterns/index.md): methods to solve common problems " +"when coding." msgstr "" +"[デザインパターン](./patterns/index.md): コーディング時のよくある問題を解決す" +"るための手法。" -#: src\intro.md:32 +#: src/intro.md:44 msgid "" -"- [Idioms](./idioms/index.md): guidelines to follow when coding.\n" -" They are the social norms of the community.\n" -" You should break them only if you have a good reason for it.\n" -"- [Design patterns](./patterns/index.md): methods to solve common problems\n" -" when coding.\n" -"- [Anti-patterns](./anti_patterns/index.md): methods to solve common " -"problems\n" -" when coding.\n" -" However, while design patterns give us benefits,\n" -" anti-patterns create more problems." +"[Anti-patterns](./anti_patterns/index.md): methods to solve common problems " +"when coding. However, while design patterns give us benefits, anti-patterns " +"create more problems." msgstr "" +"[アンチパターン](./anti_patterns/index.md): コーディング時のよくある問題を解" +"決するための手法。ただし、デザインパターンが利益をもたらすのに対して、アンチ" +"パターンは利益を超える問題を引き起こします。" -#: src\translations.md:1 -msgid "# Translations" +#: src/intro.md:48 +msgid "" +"https://web.archive.org/web/20240124025806/https://www.infoq.com/podcasts/" +"software-architecture-hard-parts/" msgstr "" -#: src\translations.md:3 +#: src/translations.md:3 msgid "" "We are utilizing [mdbook-i18n-helper](https://github.com/google/mdbook-i18n-" -"helpers).\n" -"Please read up on how to _add_ and _update_ translations in [their " +"helpers). Please read up on how to _add_ and _update_ translations in [their " "repository](https://github.com/google/mdbook-i18n-helpers#creating-and-" "updating-translations)" msgstr "" +"本書では、[mdbook-i18n-helper](https://github.com/google/mdbook-i18n-" +"helpers) を使用して翻訳管理を行っています。翻訳の _追加_ や _更新_ について" +"は、[該当リポジトリ](https://github.com/google/mdbook-i18n-helpers#creating-" +"and-updating-translations)のドキュメントをお読みください。" -#: src\translations.md:6 -msgid "## External translations" -msgstr "" +#: src/translations.md:8 +msgid "External translations" +msgstr "外部の翻訳" -#: src\translations.md:8 -msgid "- [简体中文](https://fomalhauthmj.github.io/patterns/)" +#: src/translations.md:10 +msgid "[简体中文](https://fomalhauthmj.github.io/patterns/)" msgstr "" -#: src\translations.md:10 +#: src/translations.md:12 msgid "" -"If you want to add a translation, please open an issue in the\n" -"[main repository](https://github.com/rust-unofficial/patterns)." -msgstr "" - -#: src\idioms/index.md:1 -msgid "# Idioms" +"If you want to add a translation, please open an issue in the [main " +"repository](https://github.com/rust-unofficial/patterns)." msgstr "" +"他の言語への翻訳を追加したい場合は、[メインリポジトリ](https://github.com/" +"rust-unofficial/patterns)に issue を作成してください。" -#: src\idioms/index.md:3 +#: src/idioms/index.md:3 msgid "" -"[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used\n" -"styles, guidelines and patterns largely agreed upon by a community.\n" -"Writing idiomatic code allows other developers to understand better what is\n" +"[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used " +"styles, guidelines and patterns largely agreed upon by a community. Writing " +"idiomatic code allows other developers to understand better what is " "happening." msgstr "" -#: src\idioms/index.md:8 +#: src/idioms/index.md:7 msgid "" -"After all, the computer only cares about the machine code that is generated\n" -"by the compiler.\n" -"Instead, the source code is mainly beneficial to the developer.\n" -"So, since we have this abstraction layer, why not make it more readable?" +"After all, the computer only cares about the machine code that is generated " +"by the compiler. Instead, the source code is mainly beneficial to the " +"developer. So, since we have this abstraction layer, why not make it more " +"readable?" msgstr "" -#: src\idioms/index.md:13 +#: src/idioms/index.md:11 msgid "" -"Remember the [KISS principle](https://en.wikipedia.org/wiki/" -"KISS_principle):\n" +"Remember the [KISS principle](https://en.wikipedia.org/wiki/KISS_principle): " "\"Keep It Simple, Stupid\". It claims that \"most systems work best if they " -"are\n" -"kept simple rather than made complicated; therefore, simplicity should be a " -"key\n" -"goal in design, and unnecessary complexity should be avoided\"." -msgstr "" - -#: src\idioms/index.md:18 -msgid "> Code is there for humans, not computers, to understand." +"are kept simple rather than made complicated; therefore, simplicity should " +"be a key goal in design, and unnecessary complexity should be avoided\"." msgstr "" -#: src\idioms/coercion-arguments.md:1 -msgid "# Use borrowed types for arguments" +#: src/idioms/index.md:16 +msgid "Code is there for humans, not computers, to understand." msgstr "" -#: src\idioms/coercion-arguments.md:3 src\idioms/concat-format.md:3 -#: src\idioms/default.md:3 src\idioms/deref.md:3 src\idioms/dtor-finally.md:3 -#: src\idioms/mem-replace.md:3 src\idioms/on-stack-dyn-dispatch.md:3 -#: src\idioms/ffi/errors.md:3 src\idioms/ffi/accepting-strings.md:3 -#: src\idioms/ffi/passing-strings.md:3 src\idioms/option-iter.md:3 -#: src\idioms/pass-var-to-closure.md:3 src\idioms/priv-extend.md:3 -#: src\idioms/temporary-mutability.md:3 -#: src\idioms/return-consumed-arg-on-error.md:3 -#: src\patterns/behavioural/command.md:3 -#: src\patterns/behavioural/interpreter.md:3 -#: src\patterns/behavioural/newtype.md:13 src\patterns/behavioural/RAII.md:3 -#: src\patterns/behavioural/strategy.md:3 src\patterns/behavioural/visitor.md:3 -#: src\patterns/creational/builder.md:3 src\patterns/creational/fold.md:3 -#: src\patterns/structural/compose-structs.md:5 -#: src\patterns/structural/small-crates.md:3 -#: src\patterns/structural/unsafe-mods.md:3 src\patterns/ffi/export.md:3 -#: src\patterns/ffi/wrappers.md:3 src\anti_patterns/borrow_clone.md:3 -#: src\anti_patterns/deny-warnings.md:3 src\anti_patterns/deref.md:3 -#: src\functional/generics-type-classes.md:3 -msgid "## Description" +#: src/idioms/coercion-arguments.md:3 src/idioms/concat-format.md:3 +#: src/idioms/ctor.md:3 src/idioms/default.md:3 src/idioms/deref.md:3 +#: src/idioms/dtor-finally.md:3 src/idioms/mem-replace.md:3 +#: src/idioms/on-stack-dyn-dispatch.md:3 src/idioms/ffi/errors.md:3 +#: src/idioms/ffi/accepting-strings.md:3 src/idioms/ffi/passing-strings.md:3 +#: src/idioms/option-iter.md:3 src/idioms/pass-var-to-closure.md:3 +#: src/idioms/priv-extend.md:3 src/idioms/rustdoc-init.md:3 +#: src/idioms/temporary-mutability.md:3 +#: src/idioms/return-consumed-arg-on-error.md:3 +#: src/patterns/behavioural/command.md:3 +#: src/patterns/behavioural/interpreter.md:3 +#: src/patterns/behavioural/newtype.md:13 src/patterns/behavioural/RAII.md:3 +#: src/patterns/behavioural/strategy.md:3 src/patterns/behavioural/visitor.md:3 +#: src/patterns/creational/builder.md:3 src/patterns/creational/fold.md:3 +#: src/patterns/structural/compose-structs.md:3 +#: src/patterns/structural/small-crates.md:3 +#: src/patterns/structural/unsafe-mods.md:3 src/patterns/ffi/export.md:3 +#: src/patterns/ffi/wrappers.md:3 src/anti_patterns/borrow_clone.md:3 +#: src/anti_patterns/deny-warnings.md:3 src/anti_patterns/deref.md:3 +#: src/functional/generics-type-classes.md:3 +msgid "Description" msgstr "" -#: src\idioms/coercion-arguments.md:5 +#: src/idioms/coercion-arguments.md:5 msgid "" -"Using a target of a deref coercion can increase the flexibility of your " -"code\n" -"when you are deciding which argument type to use for a function argument.\n" -"In this way, the function will accept more input types." +"Using a target of a deref coercion can increase the flexibility of your code " +"when you are deciding which argument type to use for a function argument. In " +"this way, the function will accept more input types." msgstr "" -#: src\idioms/coercion-arguments.md:9 +#: src/idioms/coercion-arguments.md:9 msgid "" -"This is not limited to slice-able or fat pointer types.\n" -"In fact, you should always prefer using the **borrowed type** over\n" -"**borrowing the owned type**.\n" +"This is not limited to slice-able or fat pointer types. In fact, you should " +"always prefer using the **borrowed type** over **borrowing the owned type**. " "Such as `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`." msgstr "" -#: src\idioms/coercion-arguments.md:14 +#: src/idioms/coercion-arguments.md:13 msgid "" -"Using borrowed types you can avoid layers of indirection for those " -"instances\n" +"Using borrowed types you can avoid layers of indirection for those instances " "where the owned type already provides a layer of indirection. For instance, " -"a\n" -"`String` has a layer of indirection, so a `&String` will have two layers of\n" -"indirection. We can avoid this by using `&str` instead, and letting " -"`&String`\n" -"coerce to a `&str` whenever the function is invoked." -msgstr "" - -#: src\idioms/coercion-arguments.md:20 src\idioms/concat-format.md:10 -#: src\idioms/default.md:20 src\idioms/deref.md:9 src\idioms/dtor-finally.md:9 -#: src\idioms/mem-replace.md:11 src\idioms/on-stack-dyn-dispatch.md:10 -#: src\idioms/pass-var-to-closure.md:12 src\idioms/priv-extend.md:18 -#: src\idioms/temporary-mutability.md:12 -#: src\idioms/return-consumed-arg-on-error.md:8 -#: src\patterns/behavioural/command.md:18 -#: src\patterns/behavioural/newtype.md:18 src\patterns/behavioural/RAII.md:11 -#: src\patterns/behavioural/strategy.md:28 -#: src\patterns/behavioural/visitor.md:13 src\patterns/creational/builder.md:7 -#: src\patterns/creational/fold.md:12 -#: src\patterns/structural/compose-structs.md:17 -#: src\anti_patterns/borrow_clone.md:11 src\anti_patterns/deny-warnings.md:8 -#: src\anti_patterns/deref.md:8 src\functional/generics-type-classes.md:38 -msgid "## Example" -msgstr "" - -#: src\idioms/coercion-arguments.md:22 +"a `String` has a layer of indirection, so a `&String` will have two layers " +"of indirection. We can avoid this by using `&str` instead, and letting " +"`&String` coerce to a `&str` whenever the function is invoked." +msgstr "" + +#: src/idioms/coercion-arguments.md:19 src/idioms/concat-format.md:10 +#: src/idioms/default.md:20 src/idioms/deref.md:9 src/idioms/dtor-finally.md:9 +#: src/idioms/mem-replace.md:11 src/idioms/on-stack-dyn-dispatch.md:10 +#: src/idioms/pass-var-to-closure.md:12 src/idioms/priv-extend.md:19 +#: src/idioms/rustdoc-init.md:45 src/idioms/temporary-mutability.md:12 +#: src/idioms/return-consumed-arg-on-error.md:8 +#: src/patterns/behavioural/command.md:18 +#: src/patterns/behavioural/newtype.md:18 src/patterns/behavioural/RAII.md:12 +#: src/patterns/behavioural/strategy.md:30 +#: src/patterns/behavioural/visitor.md:13 src/patterns/creational/builder.md:7 +#: src/patterns/creational/fold.md:12 +#: src/patterns/structural/compose-structs.md:15 +#: src/anti_patterns/borrow_clone.md:11 src/anti_patterns/deny-warnings.md:8 +#: src/anti_patterns/deref.md:8 src/functional/generics-type-classes.md:38 +msgid "Example" +msgstr "" + +#: src/idioms/coercion-arguments.md:21 msgid "" "For this example, we will illustrate some differences for using `&String` as " -"a\n" -"function argument versus using a `&str`, but the ideas apply as well to " -"using\n" -"`&Vec` versus using a `&[T]` or using a `&Box` versus a `&T`." +"a function argument versus using a `&str`, but the ideas apply as well to " +"using `&Vec` versus using a `&[T]` or using a `&Box` versus a `&T`." msgstr "" -#: src\idioms/coercion-arguments.md:26 +#: src/idioms/coercion-arguments.md:25 msgid "" -"Consider an example where we wish to determine if a word contains three\n" -"consecutive vowels. We don't need to own the string to determine this, so " -"we\n" +"Consider an example where we wish to determine if a word contains three " +"consecutive vowels. We don't need to own the string to determine this, so we " "will take a reference." msgstr "" -#: src\idioms/coercion-arguments.md:30 +#: src/idioms/coercion-arguments.md:29 msgid "The code might look something like this:" msgstr "" -#: src\idioms/coercion-arguments.md:32 -msgid "" -"```rust\n" -"fn three_vowels(word: &String) -> bool {\n" -" let mut vowel_count = 0;\n" -" for c in word.chars() {\n" -" match c {\n" -" 'a' | 'e' | 'i' | 'o' | 'u' => {\n" -" vowel_count += 1;\n" -" if vowel_count >= 3 {\n" -" return true\n" -" }\n" -" }\n" -" _ => vowel_count = 0\n" -" }\n" -" }\n" -" false\n" -"}\n" -"\n" -"fn main() {\n" -" let ferris = \"Ferris\".to_string();\n" -" let curious = \"Curious\".to_string();\n" -" println!(\"{}: {}\", ferris, three_vowels(&ferris));\n" -" println!(\"{}: {}\", curious, three_vowels(&curious));\n" -"\n" -" // This works fine, but the following two lines would fail:\n" +#: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 +msgid "'a'" +msgstr "" + +#: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 +msgid "'e'" +msgstr "" + +#: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 +msgid "'i'" +msgstr "" + +#: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 +msgid "'o'" +msgstr "" + +#: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 +msgid "'u'" +msgstr "" + +#: src/idioms/coercion-arguments.md:49 +msgid "\"Ferris\"" +msgstr "" + +#: src/idioms/coercion-arguments.md:50 +msgid "\"Curious\"" +msgstr "" + +#: src/idioms/coercion-arguments.md:51 src/idioms/coercion-arguments.md:52 +msgid "\"{}: {}\"" +msgstr "" + +#: src/idioms/coercion-arguments.md:54 +msgid "" +"// This works fine, but the following two lines would fail:\n" " // println!(\"Ferris: {}\", three_vowels(\"Ferris\"));\n" " // println!(\"Curious: {}\", three_vowels(\"Curious\"));\n" -"\n" -"}\n" -"```" msgstr "" -#: src\idioms/coercion-arguments.md:62 +#: src/idioms/coercion-arguments.md:60 msgid "" -"This works fine because we are passing a `&String` type as a parameter.\n" -"If we remove the comments on the last two lines, the example will fail. " -"This\n" -"is because a `&str` type will not coerce to a `&String` type. We can fix " -"this\n" +"This works fine because we are passing a `&String` type as a parameter. If " +"we remove the comments on the last two lines, the example will fail. This is " +"because a `&str` type will not coerce to a `&String` type. We can fix this " "by simply modifying the type for our argument." msgstr "" -#: src\idioms/coercion-arguments.md:67 +#: src/idioms/coercion-arguments.md:65 msgid "For instance, if we change our function declaration to:" msgstr "" -#: src\idioms/coercion-arguments.md:69 -msgid "" -"```rust, ignore\n" -"fn three_vowels(word: &str) -> bool {\n" -"```" -msgstr "" - -#: src\idioms/coercion-arguments.md:73 +#: src/idioms/coercion-arguments.md:71 msgid "then both versions will compile and print the same output." msgstr "" -#: src\idioms/coercion-arguments.md:75 +#: src/idioms/coercion-arguments.md:78 msgid "" -"```bash\n" -"Ferris: false\n" -"Curious: true\n" -"```" -msgstr "" - -#: src\idioms/coercion-arguments.md:80 -msgid "" -"But wait, that's not all! There is more to this story.\n" -"It's likely that you may say to yourself: that doesn't matter, I will never " -"be\n" -"using a `&'static str` as an input anyways (as we did when we used " -"`\"Ferris\"`).\n" -"Even ignoring this special example, you may still find that using `&str` " -"will\n" +"But wait, that's not all! There is more to this story. It's likely that you " +"may say to yourself: that doesn't matter, I will never be using a `&'static " +"str` as an input anyways (as we did when we used `\"Ferris\"`). Even " +"ignoring this special example, you may still find that using `&str` will " "give you more flexibility than using a `&String`." msgstr "" -#: src\idioms/coercion-arguments.md:86 +#: src/idioms/coercion-arguments.md:84 msgid "" -"Let's now take an example where someone gives us a sentence, and we want to\n" +"Let's now take an example where someone gives us a sentence, and we want to " "determine if any of the words in the sentence contain three consecutive " -"vowels.\n" -"We probably should make use of the function we have already defined and " -"simply\n" -"feed in each word from the sentence." +"vowels. We probably should make use of the function we have already defined " +"and simply feed in each word from the sentence." msgstr "" -#: src\idioms/coercion-arguments.md:91 +#: src/idioms/coercion-arguments.md:89 msgid "An example of this could look like this:" msgstr "" -#: src\idioms/coercion-arguments.md:93 -msgid "" -"```rust\n" -"fn three_vowels(word: &str) -> bool {\n" -" let mut vowel_count = 0;\n" -" for c in word.chars() {\n" -" match c {\n" -" 'a' | 'e' | 'i' | 'o' | 'u' => {\n" -" vowel_count += 1;\n" -" if vowel_count >= 3 {\n" -" return true\n" -" }\n" -" }\n" -" _ => vowel_count = 0\n" -" }\n" -" }\n" -" false\n" -"}\n" -"\n" -"fn main() {\n" -" let sentence_string =\n" -" \"Once upon a time, there was a friendly curious crab named " -"Ferris\".to_string();\n" -" for word in sentence_string.split(' ') {\n" -" if three_vowels(word) {\n" -" println!(\"{} has three consecutive vowels!\", word);\n" -" }\n" -" }\n" -"}\n" -"```" +#: src/idioms/coercion-arguments.md:110 +msgid "\"Once upon a time, there was a friendly curious crab named Ferris\"" msgstr "" -#: src\idioms/coercion-arguments.md:121 -msgid "" -"Running this example using our function declared with an argument type " -"`&str`\n" -"will yield" +#: src/idioms/coercion-arguments.md:111 +msgid "' '" msgstr "" -#: src\idioms/coercion-arguments.md:124 +#: src/idioms/coercion-arguments.md:113 +msgid "\"{word} has three consecutive vowels!\"" +msgstr "" + +#: src/idioms/coercion-arguments.md:119 msgid "" -"```bash\n" -"curious has three consecutive vowels!\n" -"```" +"Running this example using our function declared with an argument type " +"`&str` will yield" msgstr "" -#: src\idioms/coercion-arguments.md:128 +#: src/idioms/coercion-arguments.md:126 msgid "" -"However, this example will not run when our function is declared with an\n" +"However, this example will not run when our function is declared with an " "argument type `&String`. This is because string slices are a `&str` and not " -"a\n" -"`&String` which would require an allocation to be converted to `&String` " -"which\n" -"is not implicit, whereas converting from `String` to `&str` is cheap and " -"implicit." +"a `&String` which would require an allocation to be converted to `&String` " +"which is not implicit, whereas converting from `String` to `&str` is cheap " +"and implicit." msgstr "" -#: src\idioms/coercion-arguments.md:133 src\idioms/default.md:58 -#: src\idioms/deref.md:76 src\idioms/dtor-finally.md:88 -#: src\idioms/mem-replace.md:108 src\idioms/on-stack-dyn-dispatch.md:83 -#: src\idioms/option-iter.md:46 src\idioms/priv-extend.md:120 -#: src\patterns/behavioural/command.md:218 -#: src\patterns/behavioural/interpreter.md:142 -#: src\patterns/behavioural/newtype.md:104 src\patterns/behavioural/RAII.md:111 -#: src\patterns/behavioural/strategy.md:174 -#: src\patterns/behavioural/visitor.md:106 -#: src\patterns/creational/builder.md:108 src\patterns/creational/fold.md:109 -#: src\patterns/structural/small-crates.md:45 -#: src\patterns/structural/unsafe-mods.md:32 -#: src\anti_patterns/borrow_clone.md:68 src\anti_patterns/deny-warnings.md:96 -#: src\anti_patterns/deref.md:123 src\functional/generics-type-classes.md:237 -msgid "## See also" +#: src/idioms/coercion-arguments.md:132 src/idioms/ctor.md:101 +#: src/idioms/default.md:58 src/idioms/deref.md:76 +#: src/idioms/dtor-finally.md:93 src/idioms/mem-replace.md:116 +#: src/idioms/on-stack-dyn-dispatch.md:80 src/idioms/option-iter.md:47 +#: src/idioms/priv-extend.md:118 src/patterns/behavioural/command.md:218 +#: src/patterns/behavioural/interpreter.md:144 +#: src/patterns/behavioural/newtype.md:94 src/patterns/behavioural/RAII.md:112 +#: src/patterns/behavioural/strategy.md:178 +#: src/patterns/behavioural/visitor.md:108 +#: src/patterns/creational/builder.md:109 src/patterns/creational/fold.md:109 +#: src/patterns/structural/small-crates.md:45 +#: src/patterns/structural/unsafe-mods.md:33 +#: src/anti_patterns/borrow_clone.md:65 src/anti_patterns/deny-warnings.md:101 +#: src/anti_patterns/deref.md:124 src/functional/generics-type-classes.md:236 +msgid "See also" msgstr "" -#: src\idioms/coercion-arguments.md:135 +#: src/idioms/coercion-arguments.md:134 msgid "" -"- [Rust Language Reference on Type Coercions](https://doc.rust-lang.org/" -"reference/type-coercions.html)\n" -"- For more discussion on how to handle `String` and `&str` see\n" -" [this blog series (2015)](https://web.archive.org/web/20201112023149/" -"https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html)\n" -" by Herman J. Radtke III" +"[Rust Language Reference on Type Coercions](https://doc.rust-lang.org/" +"reference/type-coercions.html)" msgstr "" -#: src\idioms/concat-format.md:1 -msgid "# Concatenating strings with `format!`" +#: src/idioms/coercion-arguments.md:135 +msgid "" +"For more discussion on how to handle `String` and `&str` see [this blog " +"series (2015)](https://web.archive.org/web/20201112023149/https://" +"hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html) by Herman " +"J. Radtke III" +msgstr "" + +#: src/idioms/coercion-arguments.md:138 +msgid "" +"[Steve Klabnik's Blogpost on 'When should I use String vs &str?'](https://" +"archive.ph/LBpD0)" msgstr "" -#: src\idioms/concat-format.md:5 +#: src/idioms/concat-format.md:1 +#, fuzzy +msgid "Concatenating strings with `format!`" +msgstr "format! による文字列連結" + +#: src/idioms/concat-format.md:5 msgid "" "It is possible to build up strings using the `push` and `push_str` methods " -"on a\n" -"mutable `String`, or using its `+` operator. However, it is often more\n" -"convenient to use `format!`, especially where there is a mix of literal and\n" +"on a mutable `String`, or using its `+` operator. However, it is often more " +"convenient to use `format!`, especially where there is a mix of literal and " "non-literal strings." msgstr "" -#: src\idioms/concat-format.md:12 +#: src/idioms/concat-format.md:14 msgid "" -"```rust\n" -"fn say_hello(name: &str) -> String {\n" -" // We could construct the result string manually.\n" +"// We could construct the result string manually.\n" " // let mut result = \"Hello \".to_owned();\n" " // result.push_str(name);\n" " // result.push('!');\n" " // result\n" -"\n" -" // But using format! is better.\n" -" format!(\"Hello {}!\", name)\n" -"}\n" -"```" msgstr "" -#: src\idioms/concat-format.md:25 src\idioms/deref.md:43 -#: src\idioms/dtor-finally.md:42 src\idioms/mem-replace.md:83 -#: src\idioms/on-stack-dyn-dispatch.md:48 src\idioms/ffi/errors.md:131 -#: src\idioms/ffi/accepting-strings.md:68 src\idioms/ffi/passing-strings.md:68 -#: src\idioms/pass-var-to-closure.md:48 src\idioms/temporary-mutability.md:38 -#: src\idioms/return-consumed-arg-on-error.md:55 -#: src\patterns/behavioural/newtype.md:66 src\patterns/behavioural/RAII.md:78 -#: src\patterns/behavioural/strategy.md:96 -#: src\patterns/creational/builder.md:68 -#: src\patterns/structural/compose-structs.md:75 -#: src\patterns/structural/small-crates.md:12 -#: src\patterns/structural/unsafe-mods.md:11 src\patterns/ffi/export.md:111 -#: src\patterns/ffi/wrappers.md:63 src\anti_patterns/deny-warnings.md:16 -#: src\anti_patterns/deref.md:69 src\functional/generics-type-classes.md:210 -msgid "## Advantages" +#: src/idioms/concat-format.md:20 +msgid "// But using format! is better.\n" +msgstr "" + +#: src/idioms/concat-format.md:21 +msgid "\"Hello {name}!\"" +msgstr "" + +#: src/idioms/concat-format.md:25 src/idioms/deref.md:43 +#: src/idioms/dtor-finally.md:46 src/idioms/mem-replace.md:91 +#: src/idioms/on-stack-dyn-dispatch.md:43 src/idioms/ffi/errors.md:128 +#: src/idioms/ffi/accepting-strings.md:65 src/idioms/ffi/passing-strings.md:66 +#: src/idioms/pass-var-to-closure.md:48 src/idioms/rustdoc-init.md:77 +#: src/idioms/temporary-mutability.md:38 +#: src/idioms/return-consumed-arg-on-error.md:55 +#: src/patterns/behavioural/newtype.md:55 src/patterns/behavioural/RAII.md:79 +#: src/patterns/behavioural/strategy.md:98 +#: src/patterns/creational/builder.md:68 +#: src/patterns/structural/compose-structs.md:106 +#: src/patterns/structural/small-crates.md:13 +#: src/patterns/structural/unsafe-mods.md:12 src/patterns/ffi/export.md:113 +#: src/patterns/ffi/wrappers.md:64 src/anti_patterns/deny-warnings.md:16 +#: src/anti_patterns/deref.md:69 src/functional/generics-type-classes.md:209 +msgid "Advantages" msgstr "" -#: src\idioms/concat-format.md:27 +#: src/idioms/concat-format.md:27 msgid "" "Using `format!` is usually the most succinct and readable way to combine " "strings." msgstr "" -#: src\idioms/concat-format.md:29 src\idioms/deref.md:50 -#: src\idioms/dtor-finally.md:47 src\idioms/mem-replace.md:87 -#: src\idioms/on-stack-dyn-dispatch.md:54 src\idioms/ffi/errors.md:136 -#: src\idioms/ffi/accepting-strings.md:141 -#: src\idioms/ffi/passing-strings.md:103 src\idioms/pass-var-to-closure.md:57 -#: src\idioms/temporary-mutability.md:42 -#: src\idioms/return-consumed-arg-on-error.md:59 -#: src\patterns/behavioural/newtype.md:77 -#: src\patterns/behavioural/strategy.md:104 -#: src\patterns/creational/builder.md:76 -#: src\patterns/structural/compose-structs.md:81 -#: src\patterns/structural/small-crates.md:22 -#: src\patterns/structural/unsafe-mods.md:17 src\patterns/ffi/export.md:234 -#: src\patterns/ffi/wrappers.md:69 src\anti_patterns/deref.md:81 -#: src\functional/generics-type-classes.md:221 -msgid "## Disadvantages" +#: src/idioms/concat-format.md:30 src/idioms/deref.md:50 +#: src/idioms/dtor-finally.md:51 src/idioms/mem-replace.md:95 +#: src/idioms/on-stack-dyn-dispatch.md:49 src/idioms/ffi/errors.md:133 +#: src/idioms/ffi/accepting-strings.md:136 +#: src/idioms/ffi/passing-strings.md:101 src/idioms/pass-var-to-closure.md:57 +#: src/idioms/priv-extend.md:104 src/idioms/rustdoc-init.md:81 +#: src/idioms/temporary-mutability.md:42 +#: src/idioms/return-consumed-arg-on-error.md:59 +#: src/patterns/behavioural/newtype.md:66 +#: src/patterns/behavioural/strategy.md:107 +#: src/patterns/creational/builder.md:76 +#: src/patterns/structural/compose-structs.md:111 +#: src/patterns/structural/small-crates.md:22 +#: src/patterns/structural/unsafe-mods.md:18 src/patterns/ffi/export.md:236 +#: src/patterns/ffi/wrappers.md:70 src/anti_patterns/deref.md:81 +#: src/functional/generics-type-classes.md:220 +msgid "Disadvantages" msgstr "" -#: src\idioms/concat-format.md:31 +#: src/idioms/concat-format.md:32 msgid "" "It is usually not the most efficient way to combine strings - a series of " -"`push`\n" -"operations on a mutable string is usually the most efficient (especially if " -"the\n" -"string has been pre-allocated to the expected size)." -msgstr "" - -#: src\idioms/ctor.md:1 -msgid "# Constructors\r" -msgstr "" - -#: src\idioms/ctor.md:3 src\idioms/rustdoc-init.md:3 -msgid "## Description\r" -msgstr "" - -#: src\idioms/ctor.md:5 -msgid "" -"Rust does not have constructors as a language construct. Instead, the\r\n" -"convention is to use an [associated function][associated function] `new` to " -"create an object:" -msgstr "" - -#: src\idioms/ctor.md:8 -msgid "" -"````rust\r\n" -"/// Time in seconds.\r\n" -"///\r\n" -"/// # Example\r\n" -"///\r\n" -"/// ```\r\n" -"/// let s = Second::new(42);\r\n" -"/// assert_eq!(42, s.value());\r\n" -"/// ```\r\n" -"pub struct Second {\r\n" -" value: u64\r\n" -"}\r\n" -"\r\n" -"impl Second {\r\n" -" // Constructs a new instance of [`Second`].\r\n" -" // Note this is an associated function - no self.\r\n" -" pub fn new(value: u64) -> Self {\r\n" -" Self { value }\r\n" -" }\r\n" -"\r\n" -" /// Returns the value in seconds.\r\n" -" pub fn value(&self) -> u64 {\r\n" -" self.value\r\n" -" }\r\n" -"}\r\n" -"````" -msgstr "" - -#: src\idioms/ctor.md:35 -msgid "## Default Constructors\r" -msgstr "" - -#: src\idioms/ctor.md:37 -msgid "" -"Rust supports default constructors with the [`Default`][std-default] trait:" -msgstr "" - -#: src\idioms/ctor.md:39 -msgid "" -"````rust\r\n" -"/// Time in seconds.\r\n" -"///\r\n" -"/// # Example\r\n" -"///\r\n" -"/// ```\r\n" -"/// let s = Second::default();\r\n" -"/// assert_eq!(0, s.value());\r\n" -"/// ```\r\n" -"pub struct Second {\r\n" -" value: u64\r\n" -"}\r\n" -"\r\n" -"impl Second {\r\n" -" /// Returns the value in seconds.\r\n" -" pub fn value(&self) -> u64 {\r\n" -" self.value\r\n" -" }\r\n" -"}\r\n" -"\r\n" -"impl Default for Second {\r\n" -" fn default() -> Self {\r\n" -" Self { value: 0 }\r\n" -" }\r\n" -"}\r\n" -"````" -msgstr "" - -#: src\idioms/ctor.md:66 -msgid "" -"`Default` can also be derived if all types of all fields implement `Default`," -"\r\n" -"like they do with `Second`:" -msgstr "" - -#: src\idioms/ctor.md:69 -msgid "" -"````rust\r\n" -"/// Time in seconds.\r\n" -"///\r\n" -"/// # Example\r\n" -"///\r\n" -"/// ```\r\n" -"/// let s = Second::default();\r\n" -"/// assert_eq!(0, s.value());\r\n" -"/// ```\r\n" -"#[derive(Default)]\r\n" -"pub struct Second {\r\n" -" value: u64\r\n" -"}\r\n" -"\r\n" -"impl Second {\r\n" -" /// Returns the value in seconds.\r\n" -" pub fn value(&self) -> u64 {\r\n" -" self.value\r\n" -" }\r\n" -"}\r\n" -"````" -msgstr "" - -#: src\idioms/ctor.md:91 -msgid "" -"**Note:** It is common and expected for types to implement both\r\n" -"`Default` and an empty `new` constructor. `new` is the constructor\r\n" -"convention in Rust, and users expect it to exist, so if it is\r\n" -"reasonable for the basic constructor to take no arguments, then it\r\n" -"should, even if it is functionally identical to default." -msgstr "" - -#: src\idioms/ctor.md:97 +"`push` operations on a mutable string is usually the most efficient " +"(especially if the string has been pre-allocated to the expected size)." +msgstr "" + +#: src/idioms/ctor.md:1 +#, fuzzy +msgid "Constructors" +msgstr "コンストラクタ" + +#: src/idioms/ctor.md:5 +msgid "" +"Rust does not have constructors as a language construct. Instead, the " +"convention is to use an [associated function](https://doc.rust-lang.org/" +"stable/book/ch05-03-method-syntax.html#associated-functions) `new` to create " +"an object:" +msgstr "" + +#: src/idioms/ctor.md:10 +msgid "" +"/// Time in seconds.\n" +"///\n" +"/// # Example\n" +"///\n" +"/// ```\n" +"/// let s = Second::new(42);\n" +"/// assert_eq!(42, s.value());\n" +"/// ```\n" +msgstr "" + +#: src/idioms/ctor.md:23 +msgid "" +"// Constructs a new instance of [`Second`].\n" +" // Note this is an associated function - no self.\n" +msgstr "" + +#: src/idioms/ctor.md:29 src/idioms/ctor.md:54 src/idioms/ctor.md:85 +msgid "/// Returns the value in seconds.\n" +msgstr "" + +#: src/idioms/ctor.md:36 +#, fuzzy +msgid "Default Constructors" +msgstr "コンストラクタ" + +#: src/idioms/ctor.md:38 +msgid "" +"Rust supports default constructors with the [`Default`](https://doc.rust-" +"lang.org/stable/std/default/trait.Default.html) trait:" +msgstr "" + +#: src/idioms/ctor.md:41 src/idioms/ctor.md:71 +msgid "" +"/// Time in seconds.\n" +"///\n" +"/// # Example\n" +"///\n" +"/// ```\n" +"/// let s = Second::default();\n" +"/// assert_eq!(0, s.value());\n" +"/// ```\n" +msgstr "" + +#: src/idioms/ctor.md:67 +msgid "" +"`Default` can also be derived if all types of all fields implement " +"`Default`, like they do with `Second`:" +msgstr "" + +#: src/idioms/ctor.md:92 +msgid "" +"**Note:** It is common and expected for types to implement both `Default` " +"and an empty `new` constructor. `new` is the constructor convention in Rust, " +"and users expect it to exist, so if it is reasonable for the basic " +"constructor to take no arguments, then it should, even if it is functionally " +"identical to default." +msgstr "" + +#: src/idioms/ctor.md:97 msgid "" "**Hint:** The advantage of implementing or deriving `Default` is that your " -"type\r\n" -"can now be used where a `Default` implementation is required, most " -"prominently,\r\n" -"any of the [`*or_default` functions in the standard library][std-or-default]." +"type can now be used where a `Default` implementation is required, most " +"prominently, any of the [`*or_default` functions in the standard library]" +"(https://doc.rust-lang.org/stable/std/?search=or_default)." msgstr "" -#: src\idioms/ctor.md:101 -msgid "## See also\r" +#: src/idioms/ctor.md:103 +msgid "" +"The [default idiom](default.md) for a more in-depth description of the " +"`Default` trait." msgstr "" -#: src\idioms/ctor.md:103 +#: src/idioms/ctor.md:106 msgid "" -"- The [default idiom](default.md) for a more in-depth description of the\r\n" -" `Default` trait.\r\n" -"\r\n" -"- The [builder pattern](../patterns/creational/builder.md) for " -"constructing\r\n" -" objects where there are multiple configurations.\r\n" -"\r\n" -"- [API Guidelines/C-COMMON-TRAITS][API Guidelines/C-COMMON-TRAITS] for\r\n" -" implementing both, `Default` and `new`.\r\n" -"\r" +"The [builder pattern](../patterns/creational/builder.md) for constructing " +"objects where there are multiple configurations." msgstr "" -#: src\idioms/default.md:1 -msgid "# The `Default` Trait" +#: src/idioms/ctor.md:109 +msgid "" +"[API Guidelines/C-COMMON-TRAITS](https://rust-lang.github.io/api-guidelines/" +"interoperability.html#types-eagerly-implement-common-traits-c-common-traits) " +"for implementing both, `Default` and `new`." msgstr "" -#: src\idioms/default.md:5 +#: src/idioms/default.md:1 +#, fuzzy +msgid "The `Default` Trait" +msgstr "Defaultトレイトの活用" + +#: src/idioms/default.md:5 msgid "" -"Many types in Rust have a [constructor]. However, this is _specific_ to the\n" -"type; Rust cannot abstract over \"everything that has a `new()` method\". " -"To\n" -"allow this, the [`Default`] trait was conceived, which can be used with\n" -"containers and other generic types (e.g. see " -"[`Option::unwrap_or_default()`]).\n" -"Notably, some containers already implement it where applicable." +"Many types in Rust have a [constructor](ctor.md). However, this is " +"_specific_ to the type; Rust cannot abstract over \"everything that has a " +"`new()` method\". To allow this, the [`Default`](https://doc.rust-lang.org/" +"stable/std/default/trait.Default.html) trait was conceived, which can be " +"used with containers and other generic types (e.g. see " +"[`Option::unwrap_or_default()`](https://doc.rust-lang.org/stable/std/option/" +"enum.Option.html#method.unwrap_or_default)). Notably, some containers " +"already implement it where applicable." msgstr "" -#: src\idioms/default.md:11 +#: src/idioms/default.md:11 msgid "" -"Not only do one-element containers like `Cow`, `Box` or `Arc` implement\n" -"`Default` for contained `Default` types, one can automatically\n" -"`#[derive(Default)]` for structs whose fields all implement it, so the more\n" +"Not only do one-element containers like `Cow`, `Box` or `Arc` implement " +"`Default` for contained `Default` types, one can automatically " +"`#[derive(Default)]` for structs whose fields all implement it, so the more " "types implement `Default`, the more useful it becomes." msgstr "" -#: src\idioms/default.md:16 +#: src/idioms/default.md:16 msgid "" -"On the other hand, constructors can take multiple arguments, while the\n" -"`default()` method does not. There can even be multiple constructors with\n" +"On the other hand, constructors can take multiple arguments, while the " +"`default()` method does not. There can even be multiple constructors with " "different names, but there can only be one `Default` implementation per type." msgstr "" -#: src\idioms/default.md:22 +#: src/idioms/default.md:24 +msgid "// note that we can simply auto-derive Default here.\n" +msgstr "" + +#: src/idioms/default.md:28 +msgid "// Option defaults to None\n" +msgstr "" + +#: src/idioms/default.md:30 +msgid "// Vecs default to empty vector\n" +msgstr "" + +#: src/idioms/default.md:32 +msgid "// Duration defaults to zero time\n" +msgstr "" + +#: src/idioms/default.md:34 +msgid "// bool defaults to false\n" +msgstr "" + +#: src/idioms/default.md:39 +msgid "// add setters here\n" +msgstr "" + +#: src/idioms/default.md:43 +msgid "// construct a new instance with default values\n" +msgstr "" + +#: src/idioms/default.md:45 +msgid "// do something with conf here\n" +msgstr "" + +#: src/idioms/default.md:47 +msgid "\"conf = {conf:#?}\"" +msgstr "" + +#: src/idioms/default.md:49 msgid "" -"```rust\n" -"use std::{path::PathBuf, time::Duration};\n" -"\n" -"// note that we can simply auto-derive Default here.\n" -"#[derive(Default, Debug, PartialEq)]\n" -"struct MyConfiguration {\n" -" // Option defaults to None\n" -" output: Option,\n" -" // Vecs default to empty vector\n" -" search_path: Vec,\n" -" // Duration defaults to zero time\n" -" timeout: Duration,\n" -" // bool defaults to false\n" -" check: bool,\n" -"}\n" -"\n" -"impl MyConfiguration {\n" -" // add setters here\n" -"}\n" -"\n" -"fn main() {\n" -" // construct a new instance with default values\n" -" let mut conf = MyConfiguration::default();\n" -" // do something with conf here\n" -" conf.check = true;\n" -" println!(\"conf = {:#?}\", conf);\n" -" \n" -" // partial initialization with default values, creates the same " -"instance\n" -" let conf1 = MyConfiguration {\n" -" check: true,\n" -" ..Default::default()\n" -" };\n" -" assert_eq!(conf, conf1);\n" -"}\n" -"```" +"// partial initialization with default values, creates the same instance\n" msgstr "" -#: src\idioms/default.md:60 +#: src/idioms/default.md:60 msgid "" -"- The [constructor] idiom is another way to generate instances that may or " -"may\n" -" not be \"default\"\n" -"- The [`Default`] documentation (scroll down for the list of implementors)\n" -"- [`Option::unwrap_or_default()`]\n" -"- [`derive(new)`]" +"The [constructor](ctor.md) idiom is another way to generate instances that " +"may or may not be \"default\"" msgstr "" -#: src\idioms/deref.md:1 -msgid "# Collections are smart pointers" +#: src/idioms/default.md:62 +msgid "" +"The [`Default`](https://doc.rust-lang.org/stable/std/default/" +"trait.Default.html) documentation (scroll down for the list of implementors)" msgstr "" -#: src\idioms/deref.md:5 +#: src/idioms/default.md:63 msgid "" -"Use the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\n" -"trait to treat collections like smart pointers, offering owning\n" -"and borrowed views of data." +"[`Option::unwrap_or_default()`](https://doc.rust-lang.org/stable/std/option/" +"enum.Option.html#method.unwrap_or_default)" msgstr "" -#: src\idioms/deref.md:11 +#: src/idioms/default.md:64 +msgid "[`derive(new)`](https://crates.io/crates/derive-new/)" +msgstr "" + +#: src/idioms/deref.md:1 +#, fuzzy +msgid "Collections are smart pointers" +msgstr "コレクションはスマートポインタである" + +#: src/idioms/deref.md:5 msgid "" -"```rust,ignore\n" -"use std::ops::Deref;\n" -"\n" -"struct Vec {\n" -" data: RawVec,\n" -" //..\n" -"}\n" -"\n" -"impl Deref for Vec {\n" -" type Target = [T];\n" -"\n" -" fn deref(&self) -> &[T] {\n" -" //..\n" -" }\n" -"}\n" -"```" +"Use the [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) trait " +"to treat collections like smart pointers, offering owning and borrowed views " +"of data." +msgstr "" + +#: src/idioms/deref.md:16 src/idioms/deref.md:23 +#: src/patterns/behavioural/RAII.md:29 src/patterns/behavioural/RAII.md:41 +#: src/patterns/behavioural/RAII.md:100 src/anti_patterns/deref.md:35 +msgid "//..\n" msgstr "" -#: src\idioms/deref.md:28 +#: src/idioms/deref.md:28 msgid "" "A `Vec` is an owning collection of `T`s, while a slice (`&[T]`) is a " -"borrowed\n" -"collection of `T`s. Implementing `Deref` for `Vec` allows implicit " -"dereferencing\n" -"from `&Vec` to `&[T]` and includes the relationship in auto-derefencing\n" -"searches. Most methods you might expect to be implemented for `Vec`s are " -"instead\n" -"implemented for slices." +"borrowed collection of `T`s. Implementing `Deref` for `Vec` allows implicit " +"dereferencing from `&Vec` to `&[T]` and includes the relationship in auto-" +"dereferencing searches. Most methods you might expect to be implemented for " +"`Vec`s are instead implemented for slices." msgstr "" -#: src\idioms/deref.md:34 +#: src/idioms/deref.md:34 msgid "Also `String` and `&str` have a similar relation." msgstr "" -#: src\idioms/deref.md:36 src\idioms/dtor-finally.md:32 -#: src\idioms/mem-replace.md:57 src\idioms/on-stack-dyn-dispatch.md:37 -#: src\idioms/ffi/accepting-strings.md:12 src\idioms/ffi/passing-strings.md:14 -#: src\idioms/return-consumed-arg-on-error.md:43 -#: src\patterns/behavioural/command.md:8 -#: src\patterns/behavioural/interpreter.md:16 -#: src\patterns/behavioural/newtype.md:56 src\patterns/behavioural/RAII.md:72 -#: src\patterns/behavioural/strategy.md:19 -#: src\patterns/behavioural/visitor.md:72 src\patterns/creational/builder.md:63 -#: src\patterns/creational/fold.md:73 -#: src\patterns/structural/compose-structs.md:71 src\patterns/ffi/export.md:15 -#: src\anti_patterns/borrow_clone.md:30 -msgid "## Motivation" +#: src/idioms/deref.md:36 src/idioms/dtor-finally.md:36 +#: src/idioms/mem-replace.md:63 src/idioms/on-stack-dyn-dispatch.md:32 +#: src/idioms/ffi/accepting-strings.md:12 src/idioms/ffi/passing-strings.md:14 +#: src/idioms/rustdoc-init.md:9 src/idioms/return-consumed-arg-on-error.md:45 +#: src/patterns/behavioural/command.md:8 +#: src/patterns/behavioural/interpreter.md:17 +#: src/patterns/behavioural/newtype.md:45 src/patterns/behavioural/RAII.md:73 +#: src/patterns/behavioural/strategy.md:21 +#: src/patterns/behavioural/visitor.md:74 src/patterns/creational/builder.md:63 +#: src/patterns/creational/fold.md:73 +#: src/patterns/structural/compose-structs.md:100 src/patterns/ffi/export.md:16 +#: src/anti_patterns/borrow_clone.md:30 +msgid "Motivation" msgstr "" -#: src\idioms/deref.md:38 +#: src/idioms/deref.md:38 msgid "" "Ownership and borrowing are key aspects of the Rust language. Data " -"structures\n" -"must account for these semantics properly to give a good user\n" +"structures must account for these semantics properly to give a good user " "experience. When implementing a data structure that owns its data, offering " -"a\n" -"borrowed view of that data allows for more flexible APIs." +"a borrowed view of that data allows for more flexible APIs." msgstr "" -#: src\idioms/deref.md:45 +#: src/idioms/deref.md:45 msgid "" -"Most methods can be implemented only for the borrowed view, they are then\n" +"Most methods can be implemented only for the borrowed view, they are then " "implicitly available for the owning view." msgstr "" -#: src\idioms/deref.md:48 +#: src/idioms/deref.md:48 msgid "Gives clients a choice between borrowing or taking ownership of data." msgstr "" -#: src\idioms/deref.md:52 +#: src/idioms/deref.md:52 msgid "" "Methods and traits only available via dereferencing are not taken into " -"account\n" -"when bounds checking, so generic programming with data structures using " -"this\n" -"pattern can get complex (see the `Borrow` and `AsRef` traits, etc.)." +"account when bounds checking, so generic programming with data structures " +"using this pattern can get complex (see the `Borrow` and `AsRef` traits, " +"etc.)." msgstr "" -#: src\idioms/deref.md:56 src\idioms/dtor-finally.md:61 -#: src\idioms/mem-replace.md:97 src\idioms/on-stack-dyn-dispatch.md:68 -#: src\idioms/priv-extend.md:85 src\patterns/behavioural/command.md:203 -#: src\patterns/behavioural/interpreter.md:103 -#: src\patterns/behavioural/newtype.md:85 src\patterns/behavioural/RAII.md:83 -#: src\patterns/behavioural/strategy.md:110 -#: src\patterns/behavioural/visitor.md:79 src\patterns/creational/builder.md:81 -#: src\patterns/creational/fold.md:85 -#: src\patterns/structural/compose-structs.md:89 src\anti_patterns/deref.md:102 -msgid "## Discussion" +#: src/idioms/deref.md:56 src/idioms/dtor-finally.md:66 +#: src/idioms/mem-replace.md:105 src/idioms/on-stack-dyn-dispatch.md:66 +#: src/idioms/priv-extend.md:87 src/idioms/rustdoc-init.md:88 +#: src/patterns/behavioural/command.md:203 +#: src/patterns/behavioural/interpreter.md:105 +#: src/patterns/behavioural/newtype.md:74 src/patterns/behavioural/RAII.md:84 +#: src/patterns/behavioural/strategy.md:113 +#: src/patterns/behavioural/visitor.md:81 src/patterns/creational/builder.md:81 +#: src/patterns/creational/fold.md:85 +#: src/patterns/structural/compose-structs.md:117 +#: src/anti_patterns/deref.md:102 +msgid "Discussion" msgstr "" -#: src\idioms/deref.md:58 +#: src/idioms/deref.md:58 msgid "" "Smart pointers and collections are analogous: a smart pointer points to a " -"single\n" -"object, whereas a collection points to many objects. From the point of view " -"of\n" -"the type system, there is little difference between the two. A collection " -"owns\n" -"its data if the only way to access each datum is via the collection and the\n" -"collection is responsible for deleting the data (even in cases of shared\n" -"ownership, some kind of borrowed view may be appropriate). If a collection " -"owns\n" -"its data, it is usually useful to provide a view of the data as borrowed so " -"that\n" -"it can be referenced multiple times." -msgstr "" - -#: src\idioms/deref.md:67 -msgid "" -"Most smart pointers (e.g., `Foo`) implement `Deref`. However,\n" +"single object, whereas a collection points to many objects. From the point " +"of view of the type system, there is little difference between the two. A " +"collection owns its data if the only way to access each datum is via the " +"collection and the collection is responsible for deleting the data (even in " +"cases of shared ownership, some kind of borrowed view may be appropriate). " +"If a collection owns its data, it is usually useful to provide a view of the " +"data as borrowed so that it can be referenced multiple times." +msgstr "" + +#: src/idioms/deref.md:67 +msgid "" +"Most smart pointers (e.g., `Foo`) implement `Deref`. However, " "collections will usually dereference to a custom type. `[T]` and `str` have " -"some\n" -"language support, but in the general case, this is not necessary. `Foo` " -"can\n" -"implement `Deref>` where `Bar` is a dynamically sized type " -"and\n" -"`&Bar` is a borrowed view of the data in `Foo`." +"some language support, but in the general case, this is not necessary. " +"`Foo` can implement `Deref>` where `Bar` is a dynamically " +"sized type and `&Bar` is a borrowed view of the data in `Foo`." msgstr "" -#: src\idioms/deref.md:73 +#: src/idioms/deref.md:73 msgid "" -"Commonly, ordered collections will implement `Index` for `Range`s to " -"provide\n" +"Commonly, ordered collections will implement `Index` for `Range`s to provide " "slicing syntax. The target will be the borrowed view." msgstr "" -#: src\idioms/deref.md:78 +#: src/idioms/deref.md:78 +msgid "[Deref polymorphism anti-pattern](../anti_patterns/deref.md)." +msgstr "" + +#: src/idioms/deref.md:79 src/anti_patterns/deref.md:130 msgid "" -"- [Deref polymorphism anti-pattern](../anti_patterns/deref.md).\n" -"- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" +"[Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" "trait.Deref.html)." msgstr "" -#: src\idioms/dtor-finally.md:1 -msgid "# Finalisation in destructors" -msgstr "" +#: src/idioms/dtor-finally.md:1 +#, fuzzy +msgid "Finalisation in destructors" +msgstr "デストラクタでの後処理" -#: src\idioms/dtor-finally.md:5 +#: src/idioms/dtor-finally.md:5 msgid "" -"Rust does not provide the equivalent to `finally` blocks - code that will " -"be\n" +"Rust does not provide the equivalent to `finally` blocks - code that will be " "executed no matter how a function is exited. Instead, an object's destructor " -"can\n" -"be used to run code that must be run before exit." +"can be used to run code that must be run before exit." msgstr "" -#: src\idioms/dtor-finally.md:11 -msgid "" -"```rust,ignore\n" -"fn bar() -> Result<(), ()> {\n" -" // These don't need to be defined inside the function.\n" -" struct Foo;\n" -"\n" -" // Implement a destructor for Foo.\n" -" impl Drop for Foo {\n" -" fn drop(&mut self) {\n" -" println!(\"exit\");\n" -" }\n" -" }\n" -"\n" -" // The dtor of _exit will run however the function `bar` is exited.\n" -" let _exit = Foo;\n" -" // Implicit return with `?` operator.\n" -" baz()?;\n" -" // Normal return.\n" -" Ok(())\n" -"}\n" -"```" +#: src/idioms/dtor-finally.md:13 +msgid "// some code\n" +msgstr "" + +#: src/idioms/dtor-finally.md:17 +msgid "// These don't need to be defined inside the function.\n" +msgstr "" + +#: src/idioms/dtor-finally.md:20 +msgid "// Implement a destructor for Foo.\n" +msgstr "" + +#: src/idioms/dtor-finally.md:23 +msgid "\"exit\"" +msgstr "" + +#: src/idioms/dtor-finally.md:27 +msgid "// The dtor of _exit will run however the function `bar` is exited.\n" +msgstr "" + +#: src/idioms/dtor-finally.md:29 +msgid "// Implicit return with `?` operator.\n" +msgstr "" + +#: src/idioms/dtor-finally.md:31 +msgid "// Normal return.\n" msgstr "" -#: src\idioms/dtor-finally.md:34 +#: src/idioms/dtor-finally.md:38 msgid "" "If a function has multiple return points, then executing code on exit " -"becomes\n" -"difficult and repetitive (and thus bug-prone). This is especially the case " -"where\n" -"return is implicit due to a macro. A common case is the `?` operator which\n" -"returns if the result is an `Err`, but continues if it is `Ok`. `?` is used " -"as\n" -"an exception handling mechanism, but unlike Java (which has `finally`), " -"there is\n" -"no way to schedule code to run in both the normal and exceptional cases.\n" -"Panicking will also exit a function early." +"becomes difficult and repetitive (and thus bug-prone). This is especially " +"the case where return is implicit due to a macro. A common case is the `?` " +"operator which returns if the result is an `Err`, but continues if it is " +"`Ok`. `?` is used as an exception handling mechanism, but unlike Java (which " +"has `finally`), there is no way to schedule code to run in both the normal " +"and exceptional cases. Panicking will also exit a function early." msgstr "" -#: src\idioms/dtor-finally.md:44 +#: src/idioms/dtor-finally.md:48 msgid "" -"Code in destructors will (nearly) always be run - copes with panics, early\n" +"Code in destructors will (nearly) always be run - copes with panics, early " "returns, etc." msgstr "" -#: src\idioms/dtor-finally.md:49 +#: src/idioms/dtor-finally.md:53 msgid "" -"It is not guaranteed that destructors will run. For example, if there is an\n" -"infinite loop in a function or if running a function crashes before exit.\n" -"Destructors are also not run in the case of a panic in an already panicking\n" -"thread. Therefore, destructors cannot be relied on as finalizers where it " -"is\n" +"It is not guaranteed that destructors will run. For example, if there is an " +"infinite loop in a function or if running a function crashes before exit. " +"Destructors are also not run in the case of a panic in an already panicking " +"thread. Therefore, destructors cannot be relied on as finalizers where it is " "absolutely essential that finalisation happens." msgstr "" -#: src\idioms/dtor-finally.md:55 +#: src/idioms/dtor-finally.md:59 msgid "" "This pattern introduces some hard to notice, implicit code. Reading a " -"function\n" -"gives no clear indication of destructors to be run on exit. This can make\n" -"debugging tricky." +"function gives no clear indication of destructors to be run on exit. This " +"can make debugging tricky." msgstr "" -#: src\idioms/dtor-finally.md:59 +#: src/idioms/dtor-finally.md:63 msgid "" "Requiring an object and `Drop` impl just for finalisation is heavy on " "boilerplate." msgstr "" -#: src\idioms/dtor-finally.md:63 +#: src/idioms/dtor-finally.md:68 msgid "" -"There is some subtlety about how exactly to store the object used as a\n" +"There is some subtlety about how exactly to store the object used as a " "finalizer. It must be kept alive until the end of the function and must then " -"be\n" -"destroyed. The object must always be a value or uniquely owned pointer " -"(e.g.,\n" -"`Box`). If a shared pointer (such as `Rc`) is used, then the finalizer " -"can\n" -"be kept alive beyond the lifetime of the function. For similar reasons, the\n" -"finalizer should not be moved or returned." +"be destroyed. The object must always be a value or uniquely owned pointer " +"(e.g., `Box`). If a shared pointer (such as `Rc`) is used, then the " +"finalizer can be kept alive beyond the lifetime of the function. For similar " +"reasons, the finalizer should not be moved or returned." msgstr "" -#: src\idioms/dtor-finally.md:70 +#: src/idioms/dtor-finally.md:75 msgid "" "The finalizer must be assigned into a variable, otherwise it will be " -"destroyed\n" -"immediately, rather than when it goes out of scope. The variable name must " -"start\n" -"with `_` if the variable is only used as a finalizer, otherwise the " -"compiler\n" -"will warn that the finalizer is never used. However, do not call the " -"variable\n" -"`_` with no suffix - in that case it will be destroyed immediately." +"destroyed immediately, rather than when it goes out of scope. The variable " +"name must start with `_` if the variable is only used as a finalizer, " +"otherwise the compiler will warn that the finalizer is never used. However, " +"do not call the variable `_` with no suffix - in that case it will be " +"destroyed immediately." msgstr "" -#: src\idioms/dtor-finally.md:76 +#: src/idioms/dtor-finally.md:81 msgid "" -"In Rust, destructors are run when an object goes out of scope. This happens\n" -"whether we reach the end of block, there is an early return, or the program\n" -"panics. When panicking, Rust unwinds the stack running destructors for each\n" +"In Rust, destructors are run when an object goes out of scope. This happens " +"whether we reach the end of block, there is an early return, or the program " +"panics. When panicking, Rust unwinds the stack running destructors for each " "object in each stack frame. So, destructors get called even if the panic " -"happens\n" -"in a function being called." +"happens in a function being called." msgstr "" -#: src\idioms/dtor-finally.md:82 +#: src/idioms/dtor-finally.md:87 msgid "" "If a destructor panics while unwinding, there is no good action to take, so " -"Rust\n" -"aborts the thread immediately, without running further destructors. This " -"means\n" -"that destructors are not absolutely guaranteed to run. It also means that " -"you\n" -"must take extra care in your destructors not to panic, since it could leave\n" -"resources in an unexpected state." +"Rust aborts the thread immediately, without running further destructors. " +"This means that destructors are not absolutely guaranteed to run. It also " +"means that you must take extra care in your destructors not to panic, since " +"it could leave resources in an unexpected state." msgstr "" -#: src\idioms/dtor-finally.md:90 +#: src/idioms/dtor-finally.md:95 msgid "[RAII guards](../patterns/behavioural/RAII.md)." msgstr "" -#: src\idioms/mem-replace.md:1 -msgid "# `mem::{take(_), replace(_)}` to keep owned values in changed enums" +#: src/idioms/mem-replace.md:1 +msgid "`mem::{take(_), replace(_)}` to keep owned values in changed enums" msgstr "" -#: src\idioms/mem-replace.md:5 +#: src/idioms/mem-replace.md:5 msgid "" -"Say we have a `&mut MyEnum` which has (at least) two variants,\n" -"`A { name: String, x: u8 }` and `B { name: String }`. Now we want to change\n" -"`MyEnum::A` to a `B` if `x` is zero, while keeping `MyEnum::B` intact." +"Say we have a `&mut MyEnum` which has (at least) two variants, `A { name: " +"String, x: u8 }` and `B { name: String }`. Now we want to change `MyEnum::A` " +"to a `B` if `x` is zero, while keeping `MyEnum::B` intact." msgstr "" -#: src\idioms/mem-replace.md:9 +#: src/idioms/mem-replace.md:9 msgid "We can do this without cloning the `name`." msgstr "" -#: src\idioms/mem-replace.md:13 +#: src/idioms/mem-replace.md:23 msgid "" -"```rust\n" -"use std::mem;\n" -"\n" -"enum MyEnum {\n" -" A { name: String, x: u8 },\n" -" B { name: String }\n" -"}\n" -"\n" -"fn a_to_b(e: &mut MyEnum) {\n" -" if let MyEnum::A { name, x: 0 } = e {\n" -" // this takes out our `name` and put in an empty String instead\n" +"// This takes out our `name` and puts in an empty String instead\n" " // (note that empty strings don't allocate).\n" " // Then, construct the new enum variant (which will\n" " // be assigned to `*e`).\n" -" *e = MyEnum::B { name: mem::take(name) }\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/mem-replace.md:32 +#: src/idioms/mem-replace.md:34 msgid "This also works with more variants:" msgstr "" -#: src\idioms/mem-replace.md:34 +#: src/idioms/mem-replace.md:49 msgid "" -"```rust\n" -"use std::mem;\n" -"\n" -"enum MultiVariateEnum {\n" -" A { name: String },\n" -" B { name: String },\n" -" C,\n" -" D\n" -"}\n" -"\n" -"fn swizzle(e: &mut MultiVariateEnum) {\n" -" use MultiVariateEnum::*;\n" -" *e = match e {\n" -" // Ownership rules do not allow taking `name` by value, but we " -"cannot\n" +"// Ownership rules do not allow taking `name` by value, but we cannot\n" " // take the value out of a mutable reference, unless we replace it:\n" -" A { name } => B { name: mem::take(name) },\n" -" B { name } => A { name: mem::take(name) },\n" -" C => D,\n" -" D => C\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/mem-replace.md:59 +#: src/idioms/mem-replace.md:65 msgid "" "When working with enums, we may want to change an enum value in place, " -"perhaps\n" -"to another variant. This is usually done in two phases to keep the borrow\n" -"checker happy. In the first phase, we observe the existing value and look " -"at\n" -"its parts to decide what to do next. In the second phase we may " -"conditionally\n" -"change the value (as in the example above)." +"perhaps to another variant. This is usually done in two phases to keep the " +"borrow checker happy. In the first phase, we observe the existing value and " +"look at its parts to decide what to do next. In the second phase we may " +"conditionally change the value (as in the example above)." msgstr "" -#: src\idioms/mem-replace.md:65 +#: src/idioms/mem-replace.md:71 msgid "" -"The borrow checker won't allow us to take out `name` of the enum (because\n" +"The borrow checker won't allow us to take out `name` of the enum (because " "_something_ must be there.) We could of course `.clone()` name and put the " -"clone\n" -"into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy " -"the borrow checker](../anti_patterns/borrow_clone.md) anti-pattern. Anyway, " -"we\n" -"can avoid the extra allocation by changing `e` with only a mutable borrow." +"clone into our `MyEnum::B`, but that would be an instance of the [Clone to " +"satisfy the borrow checker](../anti_patterns/borrow_clone.md) anti-pattern. " +"Anyway, we can avoid the extra allocation by changing `e` with only a " +"mutable borrow." msgstr "" -#: src\idioms/mem-replace.md:70 +#: src/idioms/mem-replace.md:78 msgid "" -"`mem::take` lets us swap out the value, replacing it with it's default " -"value,\n" +"`mem::take` lets us swap out the value, replacing it with its default value, " "and returning the previous value. For `String`, the default value is an " -"empty\n" -"`String`, which does not need to allocate. As a result, we get the original\n" -"`name` _as an owned value_. We can then wrap this in another enum." +"empty `String`, which does not need to allocate. As a result, we get the " +"original `name` _as an owned value_. We can then wrap this in another enum." msgstr "" -#: src\idioms/mem-replace.md:75 +#: src/idioms/mem-replace.md:83 msgid "" -"**NOTE:** `mem::replace` is very similar, but allows us to specify what to\n" -"replace the value with. An equivalent to our `mem::take` line would be\n" +"**NOTE:** `mem::replace` is very similar, but allows us to specify what to " +"replace the value with. An equivalent to our `mem::take` line would be " "`mem::replace(name, String::new())`." msgstr "" -#: src\idioms/mem-replace.md:79 +#: src/idioms/mem-replace.md:87 msgid "" -"Note, however, that if we are using an `Option` and want to replace its\n" -"value with a `None`, `Option`’s `take()` method provides a shorter and\n" -"more idiomatic alternative." +"Note, however, that if we are using an `Option` and want to replace its " +"value with a `None`, `Option`’s `take()` method provides a shorter and more " +"idiomatic alternative." msgstr "" -#: src\idioms/mem-replace.md:85 +#: src/idioms/mem-replace.md:93 msgid "" "Look ma, no allocation! Also you may feel like Indiana Jones while doing it." msgstr "" -#: src\idioms/mem-replace.md:89 +#: src/idioms/mem-replace.md:97 msgid "" -"This gets a bit wordy. Getting it wrong repeatedly will make you hate the\n" -"borrow checker. The compiler may fail to optimize away the double store,\n" -"resulting in reduced performance as opposed to what you'd do in unsafe\n" +"This gets a bit wordy. Getting it wrong repeatedly will make you hate the " +"borrow checker. The compiler may fail to optimize away the double store, " +"resulting in reduced performance as opposed to what you'd do in unsafe " "languages." msgstr "" -#: src\idioms/mem-replace.md:94 +#: src/idioms/mem-replace.md:101 msgid "" "Furthermore, the type you are taking needs to implement the [`Default` trait]" -"(./default.md). However, if the type you're working with doesn't\n" -"implement this, you can instead use `mem::replace`." +"(./default.md). However, if the type you're working with doesn't implement " +"this, you can instead use `mem::replace`." msgstr "" -#: src\idioms/mem-replace.md:99 +#: src/idioms/mem-replace.md:107 msgid "" -"This pattern is only of interest in Rust. In GC'd languages, you'd take the\n" +"This pattern is only of interest in Rust. In GC'd languages, you'd take the " "reference to the value by default (and the GC would keep track of refs), and " -"in\n" -"other low-level languages like C you'd simply alias the pointer and fix " -"things\n" -"later." +"in other low-level languages like C you'd simply alias the pointer and fix " +"things later." msgstr "" -#: src\idioms/mem-replace.md:104 +#: src/idioms/mem-replace.md:112 msgid "" "However, in Rust, we have to do a little more work to do this. An owned " -"value\n" -"may only have one owner, so to take it out, we need to put something back in " -"–\n" -"like Indiana Jones, replacing the artifact with a bag of sand." +"value may only have one owner, so to take it out, we need to put something " +"back in – like Indiana Jones, replacing the artifact with a bag of sand." msgstr "" -#: src\idioms/mem-replace.md:110 +#: src/idioms/mem-replace.md:118 msgid "" "This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/" -"borrow_clone.md)\n" -"anti-pattern in a specific case." -msgstr "" - -#: src\idioms/on-stack-dyn-dispatch.md:1 -msgid "# On-Stack Dynamic Dispatch" +"borrow_clone.md) anti-pattern in a specific case." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:5 +#: src/idioms/on-stack-dyn-dispatch.md:5 msgid "" -"We can dynamically dispatch over multiple values, however, to do so, we " -"need\n" +"We can dynamically dispatch over multiple values, however, to do so, we need " "to declare multiple variables to bind differently-typed objects. To extend " -"the\n" -"lifetime as necessary, we can use deferred conditional initialization, as " -"seen\n" -"below:" +"the lifetime as necessary, we can use deferred conditional initialization, " +"as seen below:" msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:12 -msgid "" -"```rust\n" -"use std::io;\n" -"use std::fs;\n" -"\n" -"# fn main() -> Result<(), Box> {\n" -"# let arg = \"-\";\n" -"\n" -"// These must live longer than `readable`, and thus are declared first:\n" -"let (mut stdin_read, mut file_read);\n" -"\n" -"// We need to ascribe the type to get dynamic dispatch.\n" -"let readable: &mut dyn io::Read = if arg == \"-\" {\n" -" stdin_read = io::stdin();\n" -" &mut stdin_read\n" -"} else {\n" -" file_read = fs::File::open(arg)?;\n" -" &mut file_read\n" -"};\n" -"\n" -"// Read from `readable` here.\n" -"\n" -"# Ok(())\n" -"# }\n" -"```" +#: src/idioms/on-stack-dyn-dispatch.md:17 +#: src/idioms/on-stack-dyn-dispatch.md:20 +#: src/idioms/on-stack-dyn-dispatch.md:56 +msgid "\"-\"" +msgstr "" + +#: src/idioms/on-stack-dyn-dispatch.md:18 +msgid "// We need to describe the type to get dynamic dispatch.\n" +msgstr "" + +#: src/idioms/on-stack-dyn-dispatch.md:25 +#: src/idioms/on-stack-dyn-dispatch.md:60 +msgid "// Read from `readable` here.\n" msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:39 +#: src/idioms/on-stack-dyn-dispatch.md:34 msgid "" -"Rust monomorphises code by default. This means a copy of the code will be\n" +"Rust monomorphises code by default. This means a copy of the code will be " "generated for each type it is used with and optimized independently. While " -"this\n" -"allows for very fast code on the hot path, it also bloats the code in " -"places\n" -"where performance is not of the essence, thus costing compile time and " -"cache\n" -"usage." +"this allows for very fast code on the hot path, it also bloats the code in " +"places where performance is not of the essence, thus costing compile time " +"and cache usage." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:45 +#: src/idioms/on-stack-dyn-dispatch.md:40 msgid "" "Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " -"ask\n" -"for it." +"ask for it." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:50 +#: src/idioms/on-stack-dyn-dispatch.md:45 msgid "" -"We do not need to allocate anything on the heap. Neither do we need to\n" -"initialize something we won't use later, nor do we need to monomorphize the\n" +"We do not need to allocate anything on the heap. Neither do we need to " +"initialize something we won't use later, nor do we need to monomorphize the " "whole code that follows to work with both `File` or `Stdin`." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:56 -msgid "The code needs more moving parts than the `Box`-based version:" +#: src/idioms/on-stack-dyn-dispatch.md:51 +msgid "" +"Before Rust 1.79.0, the code needed two `let` bindings with deferred " +"initialization, which made up more moving parts than the `Box`\\-based " +"version:" +msgstr "" + +#: src/idioms/on-stack-dyn-dispatch.md:55 +msgid "// We still need to ascribe the type for dynamic dispatch.\n" msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:58 -msgid "" -"```rust,ignore\n" -"// We still need to ascribe the type for dynamic dispatch.\n" -"let readable: Box = if arg == \"-\" {\n" -" Box::new(io::stdin())\n" -"} else {\n" -" Box::new(fs::File::open(arg)?)\n" -"};\n" -"// Read from `readable` here.\n" -"```" +#: src/idioms/on-stack-dyn-dispatch.md:64 +msgid "Luckily, this disadvantage is now gone. Yay!" msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:70 +#: src/idioms/on-stack-dyn-dispatch.md:68 msgid "" -"Rust newcomers will usually learn that Rust requires all variables to be\n" -"initialized _before use_, so it's easy to overlook the fact that _unused_\n" -"variables may well be uninitialized. Rust works quite hard to ensure that " -"this\n" -"works out fine and only the initialized values are dropped at the end of " -"their\n" -"scope." +"Since Rust 1.79.0, the compiler will automatically extend the lifetimes of " +"temporary values within `&` or `&mut` as long as possible within the scope " +"of the function." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:76 -msgid "The example meets all the constraints Rust places on us:" +#: src/idioms/on-stack-dyn-dispatch.md:72 +msgid "" +"This means we can simply use a `&mut` value here without worrying about " +"placing the contents into some `let` binding (which would have been needed " +"for deferred initialization, which was the solution used before that change)." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:78 +#: src/idioms/on-stack-dyn-dispatch.md:76 msgid "" -"- All variables are initialized before using (in this case borrowing) them\n" -"- Each variable only holds values of a single type. In our example, `stdin` " -"is\n" -" of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut " -"dyn Read`\n" -"- Each borrowed value outlives all the references borrowed from it" +"We still have a place for each value (even if that place is temporary), the " +"compiler knows the size of each value and each borrowed value outlives all " +"references borrowed from it." msgstr "" -#: src\idioms/on-stack-dyn-dispatch.md:85 +#: src/idioms/on-stack-dyn-dispatch.md:82 msgid "" -"- [Finalisation in destructors](dtor-finally.md) and\n" -" [RAII guards](../patterns/behavioural/RAII.md) can benefit from tight " -"control over\n" -" lifetimes.\n" -"- For conditionally filled `Option<&T>`s of (mutable) references, one can\n" -" initialize an `Option` directly and use its [`.as_ref()`] method to get " -"an\n" -" optional reference." +"[Finalisation in destructors](dtor-finally.md) and [RAII guards](../patterns/" +"behavioural/RAII.md) can benefit from tight control over lifetimes." msgstr "" -#: src\idioms/ffi/intro.md:1 -msgid "# FFI Idioms" +#: src/idioms/on-stack-dyn-dispatch.md:85 +msgid "" +"For conditionally filled `Option<&T>`s of (mutable) references, one can " +"initialize an `Option` directly and use its [`.as_ref()`](https://" +"doc.rust-lang.org/std/option/enum.Option.html#method.as_ref) method to get " +"an optional reference." msgstr "" -#: src\idioms/ffi/intro.md:3 +#: src/idioms/ffi/intro.md:1 +#, fuzzy +msgid "FFI Idioms" +msgstr "慣習" + +#: src/idioms/ffi/intro.md:3 msgid "" -"Writing FFI code is an entire course in itself.\n" -"However, there are several idioms here that can act as pointers, and avoid\n" -"traps for inexperienced users of `unsafe` Rust." +"Writing FFI code is an entire course in itself. However, there are several " +"idioms here that can act as pointers, and avoid traps for inexperienced " +"users of `unsafe` Rust." msgstr "" -#: src\idioms/ffi/intro.md:7 +#: src/idioms/ffi/intro.md:7 msgid "This section contains idioms that may be useful when doing FFI." msgstr "" -#: src\idioms/ffi/intro.md:9 +#: src/idioms/ffi/intro.md:9 msgid "" -"1. [Idiomatic Errors](./errors.md) - Error handling with integer codes and\n" -" sentinel return values (such as `NULL` pointers)\n" -"\n" -"2. [Accepting Strings](./accepting-strings.md) with minimal unsafe code\n" -"\n" -"3. [Passing Strings](./passing-strings.md) to FFI functions" +"[Idiomatic Errors](./errors.md) - Error handling with integer codes and " +"sentinel return values (such as `NULL` pointers)" +msgstr "" + +#: src/idioms/ffi/intro.md:12 +msgid "[Accepting Strings](./accepting-strings.md) with minimal unsafe code" msgstr "" -#: src\idioms/ffi/errors.md:1 -msgid "# Error Handling in FFI" +#: src/idioms/ffi/intro.md:14 +msgid "[Passing Strings](./passing-strings.md) to FFI functions" msgstr "" -#: src\idioms/ffi/errors.md:5 +#: src/idioms/ffi/errors.md:1 +msgid "Error Handling in FFI" +msgstr "" + +#: src/idioms/ffi/errors.md:5 msgid "" -"In foreign languages like C, errors are represented by return codes.\n" -"However, Rust's type system allows much more rich error information to be\n" -"captured and propogated through a full type." +"In foreign languages like C, errors are represented by return codes. " +"However, Rust's type system allows much more rich error information to be " +"captured and propagated through a full type." msgstr "" -#: src\idioms/ffi/errors.md:9 +#: src/idioms/ffi/errors.md:9 msgid "" "This best practice shows different kinds of error codes, and how to expose " -"them\n" -"in a usable way:" +"them in a usable way:" +msgstr "" + +#: src/idioms/ffi/errors.md:12 +msgid "Flat Enums should be converted to integers and returned as codes." msgstr "" -#: src\idioms/ffi/errors.md:12 +#: src/idioms/ffi/errors.md:13 msgid "" -"1. Flat Enums should be converted to integers and returned as codes.\n" -"2. Structured Enums should be converted to an integer code with a string " -"error\n" -" message for detail.\n" -"3. Custom Error Types should become \"transparent\", with a C representation." +"Structured Enums should be converted to an integer code with a string error " +"message for detail." msgstr "" -#: src\idioms/ffi/errors.md:17 src\idioms/ffi/accepting-strings.md:29 -#: src\idioms/ffi/passing-strings.md:26 src\patterns/ffi/export.md:40 -#: src\patterns/ffi/wrappers.md:23 -msgid "## Code Example" +#: src/idioms/ffi/errors.md:15 +msgid "" +"Custom Error Types should become \"transparent\", with a C representation." msgstr "" -#: src\idioms/ffi/errors.md:19 -msgid "### Flat Enums" +#: src/idioms/ffi/errors.md:17 src/idioms/ffi/accepting-strings.md:29 +#: src/idioms/ffi/passing-strings.md:26 src/patterns/ffi/export.md:44 +#: src/patterns/ffi/wrappers.md:24 +msgid "Code Example" msgstr "" -#: src\idioms/ffi/errors.md:21 -msgid "" -"```rust,ignore\n" -"enum DatabaseError {\n" -" IsReadOnly = 1, // user attempted a write operation\n" -" IOError = 2, // user should read the C errno() for what it was\n" -" FileCorrupted = 3, // user should run a repair tool to recover it\n" -"}\n" -"\n" -"impl From for libc::c_int {\n" -" fn from(e: DatabaseError) -> libc::c_int {\n" -" (e as i8).into()\n" -" }\n" -"}\n" -"```" +#: src/idioms/ffi/errors.md:19 +msgid "Flat Enums" +msgstr "" + +#: src/idioms/ffi/errors.md:23 +msgid "// user attempted a write operation\n" +msgstr "" + +#: src/idioms/ffi/errors.md:24 +msgid "// user should read the C errno() for what it was\n" msgstr "" -#: src\idioms/ffi/errors.md:35 -msgid "### Structured Enums" +#: src/idioms/ffi/errors.md:25 +msgid "// user should run a repair tool to recover it\n" msgstr "" -#: src\idioms/ffi/errors.md:37 +#: src/idioms/ffi/errors.md:35 +msgid "Structured Enums" +msgstr "" + +#: src/idioms/ffi/errors.md:42 +msgid "// message describing the issue\n" +msgstr "" + +#: src/idioms/ffi/errors.md:61 src/idioms/ffi/accepting-strings.md:47 +#: src/idioms/ffi/accepting-strings.md:79 src/idioms/ffi/passing-strings.md:33 +#: src/patterns/ffi/export.md:154 src/patterns/ffi/export.md:158 +#: src/patterns/ffi/export.md:165 +msgid "\"C\"" +msgstr "" + +#: src/idioms/ffi/errors.md:64 msgid "" -"```rust,ignore\n" -"pub mod errors {\n" -" enum DatabaseError {\n" -" IsReadOnly,\n" -" IOError(std::io::Error),\n" -" FileCorrupted(String), // message describing the issue\n" -" }\n" -"\n" -" impl From for libc::c_int {\n" -" fn from(e: DatabaseError) -> libc::c_int {\n" -" match e {\n" -" DatabaseError::IsReadOnly => 1,\n" -" DatabaseError::IOError(_) => 2,\n" -" DatabaseError::FileCorrupted(_) => 3,\n" -" }\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub mod c_api {\n" -" use super::errors::DatabaseError;\n" -"\n" -" #[no_mangle]\n" -" pub extern \"C\" fn db_error_description(\n" -" e: *const DatabaseError\n" -" ) -> *mut libc::c_char {\n" -"\n" -" let error: &DatabaseError = unsafe {\n" -" // SAFETY: pointer lifetime is greater than the current stack " -"frame\n" -" &*e\n" -" };\n" -"\n" -" let error_str: String = match error {\n" -" DatabaseError::IsReadOnly => {\n" -" format!(\"cannot write to read-only database\");\n" -" }\n" -" DatabaseError::IOError(e) => {\n" -" format!(\"I/O Error: {}\", e);\n" -" }\n" -" DatabaseError::FileCorrupted(s) => {\n" -" format!(\"File corrupted, run repair: {}\", &s);\n" -" }\n" -" };\n" -"\n" -" let c_error = unsafe {\n" -" // SAFETY: copying error_str to an allocated buffer with a NUL\n" -" // character at the end\n" -" let mut malloc: *mut u8 = libc::malloc(error_str.len() + 1) as " -"*mut _;\n" -"\n" -" if malloc.is_null() {\n" -" return std::ptr::null_mut();\n" -" }\n" -"\n" -" let src = error_str.as_bytes().as_ptr();\n" -"\n" -" std::ptr::copy_nonoverlapping(src, malloc, error_str.len());\n" -"\n" -" std::ptr::write(malloc.add(error_str.len()), 0);\n" -"\n" -" malloc as *mut libc::c_char\n" -" };\n" -"\n" -" c_error\n" -" }\n" -"}\n" -"```" +"// SAFETY: we assume that the lifetime of `e` is greater than\n" +" // the current stack frame.\n" +msgstr "" + +#: src/idioms/ffi/errors.md:70 +msgid "\"cannot write to read-only database\"" +msgstr "" + +#: src/idioms/ffi/errors.md:73 +msgid "\"I/O Error: {e}\"" msgstr "" -#: src\idioms/ffi/errors.md:104 -msgid "### Custom Error Types" +#: src/idioms/ffi/errors.md:76 +msgid "\"File corrupted, run repair: {}\"" msgstr "" -#: src\idioms/ffi/errors.md:106 +#: src/idioms/ffi/errors.md:83 msgid "" -"```rust,ignore\n" -"struct ParseError {\n" -" expected: char,\n" -" line: u32,\n" -" ch: u16\n" -"}\n" -"\n" -"impl ParseError { /* ... */ }\n" -"\n" -"/* Create a second version which is exposed as a C structure */\n" -"#[repr(C)]\n" -"pub struct parse_error {\n" -" pub expected: libc::c_char,\n" -" pub line: u32,\n" -" pub ch: u16\n" -"}\n" -"\n" -"impl From for parse_error {\n" -" fn from(e: ParseError) -> parse_error {\n" -" let ParseError { expected, line, ch } = e;\n" -" parse_error { expected, line, ch }\n" -" }\n" -"}\n" -"```" +"// SAFETY: copying error_bytes to an allocated buffer with a '\\0'\n" +" // byte at the end.\n" +msgstr "" + +#: src/idioms/ffi/errors.md:99 +msgid "Custom Error Types" +msgstr "" + +#: src/idioms/ffi/errors.md:109 src/idioms/ffi/accepting-strings.md:48 +#: src/idioms/ffi/accepting-strings.md:83 src/patterns/creational/builder.md:30 +#: src/patterns/ffi/export.md:137 src/patterns/ffi/export.md:139 +msgid "/* ... */" +msgstr "" + +#: src/idioms/ffi/errors.md:111 +msgid "/* Create a second version which is exposed as a C structure */" msgstr "" -#: src\idioms/ffi/errors.md:133 +#: src/idioms/ffi/errors.md:130 msgid "" -"This ensures that the foreign language has clear access to error " -"information\n" +"This ensures that the foreign language has clear access to error information " "while not compromising the Rust code's API at all." msgstr "" -#: src\idioms/ffi/errors.md:138 +#: src/idioms/ffi/errors.md:135 msgid "" -"It's a lot of typing, and some types may not be able to be converted easily\n" +"It's a lot of typing, and some types may not be able to be converted easily " "to C." msgstr "" -#: src\idioms/ffi/accepting-strings.md:1 -msgid "# Accepting Strings" -msgstr "" - -#: src\idioms/ffi/accepting-strings.md:5 +#: src/idioms/ffi/accepting-strings.md:5 msgid "" "When accepting strings via FFI through pointers, there are two principles " -"that\n" -"should be followed:" +"that should be followed:" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:8 +msgid "Keep foreign strings \"borrowed\", rather than copying them directly." msgstr "" -#: src\idioms/ffi/accepting-strings.md:8 +#: src/idioms/ffi/accepting-strings.md:9 msgid "" -"1. Keep foreign strings \"borrowed\", rather than copying them directly.\n" -"2. Minimize the amount of complexity and `unsafe` code involved in " -"converting\n" -" from a C-style string to native Rust strings." +"Minimize the amount of complexity and `unsafe` code involved in converting " +"from a C-style string to native Rust strings." msgstr "" -#: src\idioms/ffi/accepting-strings.md:14 +#: src/idioms/ffi/accepting-strings.md:14 msgid "" "The strings used in C have different behaviours to those used in Rust, " "namely:" msgstr "" -#: src\idioms/ffi/accepting-strings.md:16 +#: src/idioms/ffi/accepting-strings.md:16 +msgid "C strings are null-terminated while Rust strings store their length" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:17 +msgid "" +"C strings can contain any arbitrary non-zero byte while Rust strings must be " +"UTF-8" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:19 msgid "" -"- C strings are null-terminated while Rust strings store their length\n" -"- C strings can contain any arbitrary non-zero byte while Rust strings must " -"be\n" -" UTF-8\n" -"- C strings are accessed and manipulated using `unsafe` pointer operations\n" -" while interactions with Rust strings go through safe methods" +"C strings are accessed and manipulated using `unsafe` pointer operations " +"while interactions with Rust strings go through safe methods" msgstr "" -#: src\idioms/ffi/accepting-strings.md:22 +#: src/idioms/ffi/accepting-strings.md:22 msgid "" "The Rust standard library comes with C equivalents of Rust's `String` and " -"`&str`\n" -"called `CString` and `&CStr`, that allow us to avoid a lot of the " -"complexity\n" -"and `unsafe` code involved in converting between C strings and Rust strings." +"`&str` called `CString` and `&CStr`, that allow us to avoid a lot of the " +"complexity and `unsafe` code involved in converting between C strings and " +"Rust strings." msgstr "" -#: src\idioms/ffi/accepting-strings.md:26 +#: src/idioms/ffi/accepting-strings.md:26 msgid "" -"The `&CStr` type also allows us to work with borrowed data, meaning passing\n" +"The `&CStr` type also allows us to work with borrowed data, meaning passing " "strings between Rust and C is a zero-cost operation." msgstr "" -#: src\idioms/ffi/accepting-strings.md:31 +#: src/idioms/ffi/accepting-strings.md:34 +#: src/idioms/ffi/accepting-strings.md:77 src/idioms/ffi/passing-strings.md:31 +#: src/idioms/ffi/passing-strings.md:80 src/patterns/ffi/wrappers.md:114 +msgid "// other module content\n" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:36 msgid "" -"```rust,ignore\n" -"pub mod unsafe_module {\n" -"\n" -" // other module content\n" -"\n" -" /// Log a message at the specified level.\n" +"/// Log a message at the specified level.\n" " ///\n" " /// # Safety\n" " ///\n" @@ -1746,5467 +1558,4433 @@ msgid "" " /// - points to valid, initialized data\n" " /// - points to memory ending in a null byte\n" " /// - won't be mutated for the duration of this function call\n" -" #[no_mangle]\n" -" pub unsafe extern \"C\" fn mylib_log(\n" -" msg: *const libc::c_char,\n" -" level: libc::c_int\n" -" ) {\n" -" let level: crate::LogLevel = match level { /* ... */ };\n" -"\n" -" // SAFETY: The caller has already guaranteed this is okay (see the\n" -" // `# Safety` section of the doc-comment).\n" -" let msg_str: &str = match std::ffi::CStr::from_ptr(msg).to_str() {\n" -" Ok(s) => s,\n" -" Err(e) => {\n" -" crate::log_error(\"FFI string conversion failed\");\n" -" return;\n" -" }\n" -" };\n" -"\n" -" crate::log(msg_str, level);\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/ffi/accepting-strings.md:70 -msgid "The example is is written to ensure that:" +#: src/idioms/ffi/accepting-strings.md:50 +msgid "" +"// SAFETY: The caller has already guaranteed this is okay (see the\n" +" // `# Safety` section of the doc-comment).\n" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:55 +#: src/idioms/ffi/accepting-strings.md:105 +msgid "\"FFI string conversion failed\"" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:67 +msgid "The example is written to ensure that:" msgstr "" -#: src\idioms/ffi/accepting-strings.md:72 +#: src/idioms/ffi/accepting-strings.md:69 src/idioms/ffi/passing-strings.md:70 +msgid "The `unsafe` block is as small as possible." +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:70 msgid "" -"1. The `unsafe` block is as small as possible.\n" -"2. The pointer with an \"untracked\" lifetime becomes a \"tracked\" shared\n" -" reference" +"The pointer with an \"untracked\" lifetime becomes a \"tracked\" shared " +"reference" msgstr "" -#: src\idioms/ffi/accepting-strings.md:76 +#: src/idioms/ffi/accepting-strings.md:72 msgid "Consider an alternative, where the string is actually copied:" msgstr "" -#: src\idioms/ffi/accepting-strings.md:78 +#: src/idioms/ffi/accepting-strings.md:80 msgid "" -"```rust,ignore\n" -"pub mod unsafe_module {\n" -"\n" -" // other module content\n" -"\n" -" pub extern \"C\" fn mylib_log(msg: *const libc::c_char, level: " -"libc::c_int) {\n" -" // DO NOT USE THIS CODE.\n" +"// DO NOT USE THIS CODE.\n" " // IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG.\n" -"\n" -" let level: crate::LogLevel = match level { /* ... */ };\n" -"\n" -" let msg_len = unsafe { /* SAFETY: strlen is what it is, I guess? */\n" -" libc::strlen(msg)\n" -" };\n" -"\n" -" let mut msg_data = Vec::with_capacity(msg_len + 1);\n" -"\n" -" let msg_cstr: std::ffi::CString = unsafe {\n" -" // SAFETY: copying from a foreign pointer expected to live\n" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:85 +msgid "/* SAFETY: strlen is what it is, I guess? */" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:92 +msgid "" +"// SAFETY: copying from a foreign pointer expected to live\n" " // for the entire stack frame into owned memory\n" -" std::ptr::copy_nonoverlapping(msg, msg_data.as_mut(), msg_len);\n" -"\n" -" msg_data.set_len(msg_len + 1);\n" -"\n" -" std::ffi::CString::from_vec_with_nul(msg_data).unwrap()\n" -" }\n" -"\n" -" let msg_str: String = unsafe {\n" -" match msg_cstr.into_string() {\n" -" Ok(s) => s,\n" -" Err(e) => {\n" -" crate::log_error(\"FFI string conversion failed\");\n" -" return;\n" -" }\n" -" }\n" -" };\n" -"\n" -" crate::log(&msg_str, level);\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/ffi/accepting-strings.md:120 -msgid "This code in inferior to the original in two respects:" +#: src/idioms/ffi/accepting-strings.md:116 +msgid "This code is inferior to the original in two respects:" +msgstr "" + +#: src/idioms/ffi/accepting-strings.md:118 +msgid "" +"There is much more `unsafe` code, and more importantly, more invariants it " +"must uphold." msgstr "" -#: src\idioms/ffi/accepting-strings.md:122 +#: src/idioms/ffi/accepting-strings.md:120 msgid "" -"1. There is much more `unsafe` code, and more importantly, more invariants " -"it\n" -" must uphold.\n" -"2. Due to the extensive arithmetic required, there is a bug in this version\n" -" that cases Rust `undefined behaviour`." +"Due to the extensive arithmetic required, there is a bug in this version " +"that cases Rust `undefined behaviour`." msgstr "" -#: src\idioms/ffi/accepting-strings.md:127 +#: src/idioms/ffi/accepting-strings.md:123 msgid "" "The bug here is a simple mistake in pointer arithmetic: the string was " -"copied,\n" -"all `msg_len` bytes of it. However, the `NUL` terminator at the end was not." +"copied, all `msg_len` bytes of it. However, the `NUL` terminator at the end " +"was not." msgstr "" -#: src\idioms/ffi/accepting-strings.md:130 +#: src/idioms/ffi/accepting-strings.md:126 msgid "" "The Vector then had its size _set_ to the length of the _zero padded string_ " -"--\n" -"rather than _resized_ to it, which could have added a zero at the end.\n" -"As a result, the last byte in the Vector is uninitialized memory.\n" -"When the `CString` is created at the bottom of the block, its read of the\n" -"Vector will cause `undefined behaviour`!" +"-- rather than _resized_ to it, which could have added a zero at the end. As " +"a result, the last byte in the Vector is uninitialized memory. When the " +"`CString` is created at the bottom of the block, its read of the Vector will " +"cause `undefined behaviour`!" msgstr "" -#: src\idioms/ffi/accepting-strings.md:136 +#: src/idioms/ffi/accepting-strings.md:132 msgid "" -"Like many such issues, this would be difficult issue to track down.\n" +"Like many such issues, this would be difficult issue to track down. " "Sometimes it would panic because the string was not `UTF-8`, sometimes it " -"would\n" -"put a weird character at the end of the string, sometimes it would just\n" -"completely crash." +"would put a weird character at the end of the string, sometimes it would " +"just completely crash." msgstr "" -#: src\idioms/ffi/accepting-strings.md:143 -#: src\idioms/ffi/passing-strings.md:105 +#: src/idioms/ffi/accepting-strings.md:138 +#: src/idioms/ffi/passing-strings.md:103 msgid "None?" msgstr "" -#: src\idioms/ffi/passing-strings.md:1 -msgid "# Passing Strings" +#: src/idioms/ffi/passing-strings.md:5 +msgid "" +"When passing strings to FFI functions, there are four principles that should " +"be followed:" +msgstr "" + +#: src/idioms/ffi/passing-strings.md:8 +msgid "Make the lifetime of owned strings as long as possible." +msgstr "" + +#: src/idioms/ffi/passing-strings.md:9 +msgid "Minimize `unsafe` code during the conversion." msgstr "" -#: src\idioms/ffi/passing-strings.md:5 +#: src/idioms/ffi/passing-strings.md:10 msgid "" -"When passing strings to FFI functions, there are four principles that should " -"be\n" -"followed:" +"If the C code can modify the string data, use `Vec` instead of `CString`." msgstr "" -#: src\idioms/ffi/passing-strings.md:8 +#: src/idioms/ffi/passing-strings.md:11 msgid "" -"1. Make the lifetime of owned strings as long as possible.\n" -"2. Minimize `unsafe` code during the conversion.\n" -"3. If the C code can modify the string data, use `Vec` instead of " -"`CString`.\n" -"4. Unless the Foreign Function API requires it, the ownership of the string\n" -" should not transfer to the callee." +"Unless the Foreign Function API requires it, the ownership of the string " +"should not transfer to the callee." msgstr "" -#: src\idioms/ffi/passing-strings.md:16 +#: src/idioms/ffi/passing-strings.md:16 msgid "" -"Rust has built-in support for C-style strings with its `CString` and `CStr`\n" +"Rust has built-in support for C-style strings with its `CString` and `CStr` " "types. However, there are different approaches one can take with strings " -"that\n" -"are being sent to a foreign function call from a Rust function." +"that are being sent to a foreign function call from a Rust function." msgstr "" -#: src\idioms/ffi/passing-strings.md:20 +#: src/idioms/ffi/passing-strings.md:20 msgid "" -"The best practice is simple: use `CString` in such a way as to minimize\n" -"`unsafe` code. However, a secondary caveat is that\n" -"_the object must live long enough_, meaning the lifetime should be " -"maximized.\n" -"In addition, the documentation explains that \"round-tripping\" a `CString` " -"after\n" +"The best practice is simple: use `CString` in such a way as to minimize " +"`unsafe` code. However, a secondary caveat is that _the object must live " +"long enough_, meaning the lifetime should be maximized. In addition, the " +"documentation explains that \"round-tripping\" a `CString` after " "modification is UB, so additional work is necessary in that case." msgstr "" -#: src\idioms/ffi/passing-strings.md:28 +#: src/idioms/ffi/passing-strings.md:42 msgid "" -"```rust,ignore\n" -"pub mod unsafe_module {\n" -"\n" -" // other module content\n" -"\n" -" extern \"C\" {\n" -" fn seterr(message: *const libc::c_char);\n" -" fn geterr(buffer: *mut libc::c_char, size: libc::c_int) -> " -"libc::c_int;\n" -" }\n" -"\n" -" fn report_error_to_ffi>(\n" -" err: S\n" -" ) -> Result<(), std::ffi::NulError>{\n" -" let c_err = std::ffi::CString::new(err.into())?;\n" -"\n" -" unsafe {\n" -" // SAFETY: calling an FFI whose documentation says the pointer " -"is\n" +"// SAFETY: calling an FFI whose documentation says the pointer is\n" " // const, so no modification should occur\n" -" seterr(c_err.as_ptr());\n" -" }\n" -"\n" -" Ok(())\n" -" // The lifetime of c_err continues until here\n" -" }\n" -"\n" -" fn get_error_from_ffi() -> Result {\n" -" let mut buffer = vec![0u8; 1024];\n" -" unsafe {\n" -" // SAFETY: calling an FFI whose documentation implies\n" +msgstr "" + +#: src/idioms/ffi/passing-strings.md:48 +msgid "// The lifetime of c_err continues until here\n" +msgstr "" + +#: src/idioms/ffi/passing-strings.md:54 +msgid "" +"// SAFETY: calling an FFI whose documentation implies\n" " // that the input need only live as long as the call\n" -" let written: usize = geterr(buffer.as_mut_ptr(), 1023).into();\n" -"\n" -" buffer.truncate(written + 1);\n" -" }\n" -"\n" -" std::ffi::CString::new(buffer).unwrap().into_string()\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/ffi/passing-strings.md:70 +#: src/idioms/ffi/passing-strings.md:68 msgid "The example is written in a way to ensure that:" msgstr "" -#: src\idioms/ffi/passing-strings.md:72 -msgid "" -"1. The `unsafe` block is as small as possible.\n" -"2. The `CString` lives long enough.\n" -"3. Errors with typecasts are always propagated when possible." +#: src/idioms/ffi/passing-strings.md:71 +msgid "The `CString` lives long enough." +msgstr "" + +#: src/idioms/ffi/passing-strings.md:72 +msgid "Errors with typecasts are always propagated when possible." msgstr "" -#: src\idioms/ffi/passing-strings.md:76 +#: src/idioms/ffi/passing-strings.md:74 msgid "" -"A common mistake (so common it's in the documentation) is to not use the\n" +"A common mistake (so common it's in the documentation) is to not use the " "variable in the first block:" msgstr "" -#: src\idioms/ffi/passing-strings.md:79 -msgid "" -"```rust,ignore\n" -"pub mod unsafe_module {\n" -"\n" -" // other module content\n" -"\n" -" fn report_error>(err: S) -> Result<(), " -"std::ffi::NulError> {\n" -" unsafe {\n" -" // SAFETY: whoops, this contains a dangling pointer!\n" -" seterr(std::ffi::CString::new(err.into())?.as_ptr());\n" -" }\n" -" Ok(())\n" -" }\n" -"}\n" -"```" +#: src/idioms/ffi/passing-strings.md:84 +msgid "// SAFETY: whoops, this contains a dangling pointer!\n" msgstr "" -#: src\idioms/ffi/passing-strings.md:94 +#: src/idioms/ffi/passing-strings.md:92 msgid "" -"This code will result in a dangling pointer, because the lifetime of the\n" +"This code will result in a dangling pointer, because the lifetime of the " "`CString` is not extended by the pointer creation, unlike if a reference " -"were\n" -"created." +"were created." msgstr "" -#: src\idioms/ffi/passing-strings.md:98 +#: src/idioms/ffi/passing-strings.md:96 msgid "" -"Another issue frequently raised is that the initialization of a 1k vector " -"of\n" -"zeroes is \"slow\". However, recent versions of Rust actually optimize that\n" +"Another issue frequently raised is that the initialization of a 1k vector of " +"zeroes is \"slow\". However, recent versions of Rust actually optimize that " "particular macro to a call to `zmalloc`, meaning it is as fast as the " -"operating\n" -"system's ability to return zeroed memory (which is quite fast)." +"operating system's ability to return zeroed memory (which is quite fast)." msgstr "" -#: src\idioms/option-iter.md:1 -msgid "# Iterating over an `Option`" -msgstr "" +#: src/idioms/option-iter.md:1 +#, fuzzy +msgid "Iterating over an `Option`" +msgstr "Optionをイテレータとして使う" -#: src\idioms/option-iter.md:5 +#: src/idioms/option-iter.md:5 msgid "" -"`Option` can be viewed as a container that contains either zero or one\n" -"element. In particular, it implements the `IntoIterator` trait, and as such\n" +"`Option` can be viewed as a container that contains either zero or one " +"element. In particular, it implements the `IntoIterator` trait, and as such " "can be used with generic code that needs such a type." msgstr "" -#: src\idioms/option-iter.md:9 src\patterns/structural/small-crates.md:34 -#: src\patterns/structural/unsafe-mods.md:22 -msgid "## Examples" +#: src/idioms/option-iter.md:9 src/patterns/structural/small-crates.md:34 +#: src/patterns/structural/unsafe-mods.md:23 +msgid "Examples" msgstr "" -#: src\idioms/option-iter.md:11 +#: src/idioms/option-iter.md:11 msgid "" -"Since `Option` implements `IntoIterator`, it can be used as an argument to\n" +"Since `Option` implements `IntoIterator`, it can be used as an argument to " "[`.extend()`](https://doc.rust-lang.org/std/iter/" "trait.Extend.html#tymethod.extend):" msgstr "" -#: src\idioms/option-iter.md:14 -msgid "" -"```rust\n" -"let turing = Some(\"Turing\");\n" -"let mut logicians = vec![\"Curry\", \"Kleene\", \"Markov\"];\n" -"\n" -"logicians.extend(turing);\n" -"\n" -"// equivalent to\n" -"if let Some(turing_inner) = turing {\n" -" logicians.push(turing_inner);\n" -"}\n" -"```" +#: src/idioms/option-iter.md:15 src/idioms/option-iter.md:31 +msgid "\"Turing\"" +msgstr "" + +#: src/idioms/option-iter.md:16 src/idioms/option-iter.md:32 +msgid "\"Curry\"" +msgstr "" + +#: src/idioms/option-iter.md:16 src/idioms/option-iter.md:32 +msgid "\"Kleene\"" +msgstr "" + +#: src/idioms/option-iter.md:16 src/idioms/option-iter.md:32 +msgid "\"Markov\"" +msgstr "" + +#: src/idioms/option-iter.md:19 +msgid "// equivalent to\n" msgstr "" -#: src\idioms/option-iter.md:26 +#: src/idioms/option-iter.md:26 msgid "" -"If you need to tack an `Option` to the end of an existing iterator, you can\n" +"If you need to tack an `Option` to the end of an existing iterator, you can " "pass it to [`.chain()`](https://doc.rust-lang.org/std/iter/" "trait.Iterator.html#method.chain):" msgstr "" -#: src\idioms/option-iter.md:29 -msgid "" -"```rust\n" -"let turing = Some(\"Turing\");\n" -"let logicians = vec![\"Curry\", \"Kleene\", \"Markov\"];\n" -"\n" -"for logician in logicians.iter().chain(turing.iter()) {\n" -" println!(\"{} is a logician\", logician);\n" -"}\n" -"```" +#: src/idioms/option-iter.md:35 +msgid "\"{logician} is a logician\"" msgstr "" -#: src\idioms/option-iter.md:38 +#: src/idioms/option-iter.md:39 msgid "" -"Note that if the `Option` is always `Some`, then it is more idiomatic to " -"use\n" -"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) on the\n" +"Note that if the `Option` is always `Some`, then it is more idiomatic to use " +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) on the " "element instead." msgstr "" -#: src\idioms/option-iter.md:42 +#: src/idioms/option-iter.md:43 msgid "" "Also, since `Option` implements `IntoIterator`, it's possible to iterate " -"over\n" -"it using a `for` loop. This is equivalent to matching it with `if let " -"Some(..)`,\n" -"and in most cases you should prefer the latter." +"over it using a `for` loop. This is equivalent to matching it with `if let " +"Some(..)`, and in most cases you should prefer the latter." msgstr "" -#: src\idioms/option-iter.md:48 +#: src/idioms/option-iter.md:49 msgid "" -"- [`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) is " -"an\n" -" iterator which yields exactly one element. It's a more readable " -"alternative to\n" -" `Some(foo).into_iter()`.\n" -"\n" -"- [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/" -"trait.Iterator.html#method.filter_map)\n" -" is a version of [`Iterator::map`](https://doc.rust-lang.org/std/iter/" -"trait.Iterator.html#method.map),\n" -" specialized to mapping functions which return `Option`.\n" -"\n" -"- The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " -"functions\n" -" for converting an `Option` to a zero- or one-element slice.\n" -"\n" -"- [Documentation for `Option`](https://doc.rust-lang.org/std/option/" -"enum.Option.html)" +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) is an " +"iterator which yields exactly one element. It's a more readable alternative " +"to `Some(foo).into_iter()`." +msgstr "" + +#: src/idioms/option-iter.md:53 +msgid "" +"[`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/" +"trait.Iterator.html#method.filter_map) is a version of [`Iterator::map`]" +"(https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map), " +"specialized to mapping functions which return `Option`." +msgstr "" + +#: src/idioms/option-iter.md:58 +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions for converting an `Option` to a zero- or one-element slice." msgstr "" -#: src\idioms/pass-var-to-closure.md:1 -msgid "# Pass variables to closure" +#: src/idioms/option-iter.md:61 +msgid "" +"[Documentation for `Option`](https://doc.rust-lang.org/std/option/" +"enum.Option.html)" msgstr "" -#: src\idioms/pass-var-to-closure.md:5 +#: src/idioms/pass-var-to-closure.md:1 +#, fuzzy +msgid "Pass variables to closure" +msgstr "クロージャの変数キャプチャ" + +#: src/idioms/pass-var-to-closure.md:5 msgid "" -"By default, closures capture their environment by borrowing. Or you can use\n" -"`move`-closure to move whole environment. However, often you want to move " -"just\n" -"some variables to closure, give it copy of some data, pass it by reference, " -"or\n" -"perform some other transformation." +"By default, closures capture their environment by borrowing. Or you can use " +"a `move`\\-closure to move the whole environment. However, often you want to " +"move just some variables to the closure, give it a copy of some data, pass " +"by reference, or perform some other transformation." msgstr "" -#: src\idioms/pass-var-to-closure.md:10 -msgid "Use variable rebinding in separate scope for that." +#: src/idioms/pass-var-to-closure.md:10 +msgid "Use variable rebinding in a separate scope for that." msgstr "" -#: src\idioms/pass-var-to-closure.md:14 +#: src/idioms/pass-var-to-closure.md:14 msgid "Use" msgstr "" -#: src\idioms/pass-var-to-closure.md:16 -msgid "" -"```rust\n" -"use std::rc::Rc;\n" -"\n" -"let num1 = Rc::new(1);\n" -"let num2 = Rc::new(2);\n" -"let num3 = Rc::new(3);\n" -"let closure = {\n" -" // `num1` is moved\n" -" let num2 = num2.clone(); // `num2` is cloned\n" -" let num3 = num3.as_ref(); // `num3` is borrowed\n" -" move || {\n" -" *num1 + *num2 + *num3;\n" -" }\n" -"};\n" -"```" +#: src/idioms/pass-var-to-closure.md:23 +msgid "// `num1` is moved\n" msgstr "" -#: src\idioms/pass-var-to-closure.md:32 -msgid "instead of" +#: src/idioms/pass-var-to-closure.md:24 +msgid "// `num2` is cloned\n" msgstr "" -#: src\idioms/pass-var-to-closure.md:34 -msgid "" -"```rust\n" -"use std::rc::Rc;\n" -"\n" -"let num1 = Rc::new(1);\n" -"let num2 = Rc::new(2);\n" -"let num3 = Rc::new(3);\n" -"\n" -"let num2_cloned = num2.clone();\n" -"let num3_borrowed = num3.as_ref();\n" -"let closure = move || {\n" -" *num1 + *num2_cloned + *num3_borrowed;\n" -"};\n" -"```" +#: src/idioms/pass-var-to-closure.md:25 +msgid "// `num3` is borrowed\n" +msgstr "" + +#: src/idioms/pass-var-to-closure.md:32 +msgid "instead of" msgstr "" -#: src\idioms/pass-var-to-closure.md:50 +#: src/idioms/pass-var-to-closure.md:50 msgid "" -"Copied data are grouped together with closure definition, so their purpose " -"is\n" -"more clear, and they will be dropped immediately even if they are not " -"consumed\n" -"by closure." +"Copied data are grouped together with the closure definition, so their " +"purpose is more clear, and they will be dropped immediately even if they are " +"not consumed by the closure." msgstr "" -#: src\idioms/pass-var-to-closure.md:54 +#: src/idioms/pass-var-to-closure.md:54 msgid "" -"Closure uses same variable names as surrounding code whether data are copied " -"or\n" -"moved." +"The closure uses the same variable names as the surrounding code, whether " +"data are copied or moved." msgstr "" -#: src\idioms/pass-var-to-closure.md:59 -msgid "Additional indentation of closure body." +#: src/idioms/pass-var-to-closure.md:59 +msgid "Additional indentation of the closure body." msgstr "" -#: src\idioms/priv-extend.md:1 -msgid "# `#[non_exhaustive]` and private fields for extensibility" +#: src/idioms/priv-extend.md:1 +msgid "`#[non_exhaustive]` and private fields for extensibility" msgstr "" -#: src\idioms/priv-extend.md:5 +#: src/idioms/priv-extend.md:5 msgid "" -"A small set of scenarios exist where a library author may want to add " -"public\n" +"A small set of scenarios exist where a library author may want to add public " "fields to a public struct or new variants to an enum without breaking " -"backwards\n" -"compatibility." +"backwards compatibility." msgstr "" -#: src\idioms/priv-extend.md:9 +#: src/idioms/priv-extend.md:9 msgid "Rust offers two solutions to this problem:" msgstr "" -#: src\idioms/priv-extend.md:11 +#: src/idioms/priv-extend.md:11 msgid "" -"- Use `#[non_exhaustive]` on `struct`s, `enum`s, and `enum` variants.\n" -" For extensive documentation on all the places where `#[non_exhaustive]` " -"can be\n" -" used, see [the docs](https://doc.rust-lang.org/reference/attributes/" -"type_system.html#the-non_exhaustive-attribute).\n" -"\n" -"- You may add a private field to a struct to prevent it from being directly\n" -" instantiated or matched against (see Alternative)" -msgstr "" - -#: src\idioms/priv-extend.md:20 -msgid "" -"```rust\n" -"mod a {\n" -" // Public struct.\n" -" #[non_exhaustive]\n" -" pub struct S {\n" -" pub foo: i32,\n" -" }\n" -" \n" -" #[non_exhaustive]\n" -" pub enum AdmitMoreVariants {\n" -" VariantA,\n" -" VariantB,\n" -" #[non_exhaustive]\n" -" VariantC { a: String }\n" -" }\n" -"}\n" -"\n" -"fn print_matched_variants(s: a::S) {\n" -" // Because S is `#[non_exhaustive]`, it cannot be named here and\n" +"Use `#[non_exhaustive]` on `struct`s, `enum`s, and `enum` variants. For " +"extensive documentation on all the places where `#[non_exhaustive]` can be " +"used, see [the docs](https://doc.rust-lang.org/reference/attributes/" +"type_system.html#the-non_exhaustive-attribute)." +msgstr "" + +#: src/idioms/priv-extend.md:16 +msgid "" +"You may add a private field to a struct to prevent it from being directly " +"instantiated or matched against (see Alternative)" +msgstr "" + +#: src/idioms/priv-extend.md:23 +msgid "// Public struct.\n" +msgstr "" + +#: src/idioms/priv-extend.md:41 +msgid "" +"// Because S is `#[non_exhaustive]`, it cannot be named here and\n" " // we must use `..` in the pattern.\n" -" let a::S { foo: _, ..} = s;\n" -" \n" -" let some_enum = a::AdmitMoreVariants::VariantA;\n" -" match some_enum {\n" -" a::AdmitMoreVariants::VariantA => println!(\"it's an A\"),\n" -" a::AdmitMoreVariants::VariantB => println!(\"it's a b\"),\n" -"\n" -" // .. required because this variant is non-exhaustive as well\n" -" a::AdmitMoreVariants::VariantC { a, .. } => println!(\"it's a c\"),\n" -"\n" -" // The wildcard match is required because more variants may be\n" +msgstr "" + +#: src/idioms/priv-extend.md:47 +msgid "\"it's an A\"" +msgstr "" + +#: src/idioms/priv-extend.md:48 +msgid "\"it's a b\"" +msgstr "" + +#: src/idioms/priv-extend.md:50 +msgid "// .. required because this variant is non-exhaustive as well\n" +msgstr "" + +#: src/idioms/priv-extend.md:51 +msgid "\"it's a c\"" +msgstr "" + +#: src/idioms/priv-extend.md:53 +msgid "" +"// The wildcard match is required because more variants may be\n" " // added in the future\n" -" _ => println!(\"it's a new variant\")\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\idioms/priv-extend.md:57 -msgid "## Alternative: `Private fields` for structs" +#: src/idioms/priv-extend.md:55 +msgid "\"it's a new variant\"" msgstr "" -#: src\idioms/priv-extend.md:59 +#: src/idioms/priv-extend.md:60 +msgid "Alternative: `Private fields` for structs" +msgstr "" + +#: src/idioms/priv-extend.md:62 msgid "" -"`#[non_exhaustive]` only works across crate boundaries.\n" -"Within a crate, the private field method may be used." +"`#[non_exhaustive]` only works across crate boundaries. Within a crate, the " +"private field method may be used." msgstr "" -#: src\idioms/priv-extend.md:62 +#: src/idioms/priv-extend.md:65 msgid "" -"Adding a field to a struct is a mostly backwards compatible change.\n" -"However, if a client uses a pattern to deconstruct a struct instance, they\n" -"might name all the fields in the struct and adding a new one would break " -"that\n" -"pattern.\n" +"Adding a field to a struct is a mostly backwards compatible change. However, " +"if a client uses a pattern to deconstruct a struct instance, they might name " +"all the fields in the struct and adding a new one would break that pattern. " "The client could name some fields and use `..` in the pattern, in which case " -"adding\n" -"another field is backwards compatible.\n" -"Making at least one of the struct's fields private forces clients to use the " -"latter\n" -"form of patterns, ensuring that the struct is future-proof." +"adding another field is backwards compatible. Making at least one of the " +"struct's fields private forces clients to use the latter form of patterns, " +"ensuring that the struct is future-proof." msgstr "" -#: src\idioms/priv-extend.md:71 +#: src/idioms/priv-extend.md:73 msgid "" "The downside of this approach is that you might need to add an otherwise " -"unneeded\n" -"field to the struct.\n" -"You can use the `()` type so that there is no runtime overhead and prepend " -"`_` to\n" -"the field name to avoid the unused field warning." +"unneeded field to the struct. You can use the `()` type so that there is no " +"runtime overhead and prepend `_` to the field name to avoid the unused field " +"warning." msgstr "" -#: src\idioms/priv-extend.md:76 +#: src/idioms/priv-extend.md:81 msgid "" -"```rust\n" -"pub struct S {\n" -" pub a: i32,\n" -" // Because `b` is private, you cannot match on `S` without using `..` " -"and `S`\n" +"// Because `b` is private, you cannot match on `S` without using `..` and " +"`S`\n" " // cannot be directly instantiated or matched against\n" -" _b: ()\n" -"}\n" -"```" msgstr "" -#: src\idioms/priv-extend.md:87 +#: src/idioms/priv-extend.md:89 msgid "" "On `struct`s, `#[non_exhaustive]` allows adding additional fields in a " -"backwards\n" -"compatible way.\n" -"It will also prevent clients from using the struct constructor, even if all " -"the\n" -"fields are public.\n" -"This may be helpful, but it's worth considering if you _want_ an additional " -"field\n" -"to be found by clients as a compiler error rather than something that may be " -"silently\n" +"backwards compatible way. It will also prevent clients from using the struct " +"constructor, even if all the fields are public. This may be helpful, but " +"it's worth considering if you _want_ an additional field to be found by " +"clients as a compiler error rather than something that may be silently " "undiscovered." msgstr "" -#: src\idioms/priv-extend.md:95 +#: src/idioms/priv-extend.md:95 msgid "" -"`#[non_exhaustive]` can be applied to enum variants as well.\n" -"A `#[non_exhaustive]` variant behaves in the same way as a " -"`#[non_exhaustive]` struct." +"`#[non_exhaustive]` can be applied to enum variants as well. A " +"`#[non_exhaustive]` variant behaves in the same way as a `#[non_exhaustive]` " +"struct." msgstr "" -#: src\idioms/priv-extend.md:98 +#: src/idioms/priv-extend.md:99 msgid "" "Use this deliberately and with caution: incrementing the major version when " -"adding\n" -"fields or variants is often a better option.\n" -"`#[non_exhaustive]` may be appropriate in scenarios where you're modeling an " -"external\n" -"resource that may change out-of-sync with your library, but is not a general " -"purpose\n" -"tool." -msgstr "" - -#: src\idioms/priv-extend.md:104 -msgid "### Disadvantages" +"adding fields or variants is often a better option. `#[non_exhaustive]` may " +"be appropriate in scenarios where you're modeling an external resource that " +"may change out-of-sync with your library, but is not a general purpose tool." msgstr "" -#: src\idioms/priv-extend.md:106 +#: src/idioms/priv-extend.md:106 msgid "" "`#[non_exhaustive]` can make your code much less ergonomic to use, " -"especially when\n" -"forced to handle unknown enum variants.\n" -"It should only be used when these sorts of evolutions are required " -"**without**\n" -"incrementing the major version." +"especially when forced to handle unknown enum variants. It should only be " +"used when these sorts of evolutions are required **without** incrementing " +"the major version." msgstr "" -#: src\idioms/priv-extend.md:111 +#: src/idioms/priv-extend.md:110 msgid "" "When `#[non_exhaustive]` is applied to `enum`s, it forces clients to handle " -"a\n" -"wildcard variant.\n" -"If there is no sensible action to take in this case, this may lead to " -"awkward\n" -"code and code paths that are only executed in extremely rare circumstances.\n" -"If a client decides to `panic!()` in this scenario, it may have been better " -"to\n" -"expose this error at compile time.\n" -"In fact, `#[non_exhaustive]` forces clients to handle the \"Something else\" " -"case;\n" -"there is rarely a sensible action to take in this scenario." -msgstr "" - -#: src\idioms/priv-extend.md:122 -msgid "" -"- [RFC introducing #[non_exhaustive] attribute for enums and structs]" -"(https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" +"a wildcard variant. If there is no sensible action to take in this case, " +"this may lead to awkward code and code paths that are only executed in " +"extremely rare circumstances. If a client decides to `panic!()` in this " +"scenario, it may have been better to expose this error at compile time. In " +"fact, `#[non_exhaustive]` forces clients to handle the \"Something else\" " +"case; there is rarely a sensible action to take in this scenario." msgstr "" -#: src\idioms/rustdoc-init.md:1 -msgid "# Easy doc initialization\r" +#: src/idioms/priv-extend.md:120 +msgid "" +"[RFC introducing #\\[non_exhaustive\\] attribute for enums and structs]" +"(https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" msgstr "" -#: src\idioms/rustdoc-init.md:5 +#: src/idioms/rustdoc-init.md:5 msgid "" "If a struct takes significant effort to initialize when writing docs, it can " -"be\r\n" -"quicker to wrap your example with a helper function which takes the struct " -"as an\r\n" -"argument." +"be quicker to wrap your example with a helper function which takes the " +"struct as an argument." msgstr "" -#: src\idioms/rustdoc-init.md:9 -msgid "## Motivation\r" -msgstr "" - -#: src\idioms/rustdoc-init.md:11 +#: src/idioms/rustdoc-init.md:11 msgid "" "Sometimes there is a struct with multiple or complicated parameters and " -"several\r\n" -"methods. Each of these methods should have examples." +"several methods. Each of these methods should have examples." msgstr "" -#: src\idioms/rustdoc-init.md:14 +#: src/idioms/rustdoc-init.md:14 msgid "For example:" msgstr "" -#: src\idioms/rustdoc-init.md:16 -msgid "" -"````rust,ignore\r\n" -"struct Connection {\r\n" -" name: String,\r\n" -" stream: TcpStream,\r\n" -"}\r\n" -"\r\n" -"impl Connection {\r\n" -" /// Sends a request over the connection.\r\n" -" ///\r\n" -" /// # Example\r\n" -" /// ```no_run\r\n" -" /// # // Boilerplate are required to get an example working.\r\n" -" /// # let stream = TcpStream::connect(\"127.0.0.1:34254\");\r\n" -" /// # let connection = Connection { name: \"foo\".to_owned(), stream };" -"\r\n" +#: src/idioms/rustdoc-init.md:23 +msgid "" +"/// Sends a request over the connection.\n" +" ///\n" +" /// # Example\n" +" /// ```no_run\n" +" /// # // Boilerplate are required to get an example working.\n" +" /// # let stream = TcpStream::connect(\"127.0.0.1:34254\");\n" +" /// # let connection = Connection { name: \"foo\".to_owned(), stream };\n" " /// # let request = Request::new(\"RequestId\", RequestType::Get, " -"\"payload\");\r\n" -" /// let response = connection.send_request(request);\r\n" -" /// assert!(response.is_ok());\r\n" -" /// ```\r\n" -" fn send_request(&self, request: Request) -> Result {\r\n" -" // ...\r\n" -" }\r\n" -"\r\n" -" /// Oh no, all that boilerplate needs to be repeated here!\r\n" -" fn check_status(&self) -> Status {\r\n" -" // ...\r\n" -" }\r\n" -"}\r\n" -"````" +"\"payload\");\n" +" /// let response = connection.send_request(request);\n" +" /// assert!(response.is_ok());\n" +" /// ```\n" msgstr "" -#: src\idioms/rustdoc-init.md:45 -msgid "## Example\r" +#: src/idioms/rustdoc-init.md:35 src/idioms/rustdoc-init.md:40 +#: src/idioms/rustdoc-init.md:68 +msgid "// ...\n" msgstr "" -#: src\idioms/rustdoc-init.md:47 +#: src/idioms/rustdoc-init.md:38 +msgid "/// Oh no, all that boilerplate needs to be repeated here!\n" +msgstr "" + +#: src/idioms/rustdoc-init.md:47 msgid "" -"Instead of typing all of this boilerplate to create a `Connection` and\r\n" +"Instead of typing all of this boilerplate to create a `Connection` and " "`Request`, it is easier to just create a wrapping helper function which " -"takes\r\n" -"them as arguments:" -msgstr "" - -#: src\idioms/rustdoc-init.md:51 -msgid "" -"````rust,ignore\r\n" -"struct Connection {\r\n" -" name: String,\r\n" -" stream: TcpStream,\r\n" -"}\r\n" -"\r\n" -"impl Connection {\r\n" -" /// Sends a request over the connection.\r\n" -" ///\r\n" -" /// # Example\r\n" -" /// ```\r\n" -" /// # fn call_send(connection: Connection, request: Request) {\r\n" -" /// let response = connection.send_request(request);\r\n" -" /// assert!(response.is_ok());\r\n" -" /// # }\r\n" -" /// ```\r\n" -" fn send_request(&self, request: Request) {\r\n" -" // ...\r\n" -" }\r\n" -"}\r\n" -"````" -msgstr "" - -#: src\idioms/rustdoc-init.md:73 -msgid "" -"**Note** in the above example the line `assert!(response.is_ok());` will " -"not\r\n" -"actually run while testing because it is inside a function which is never\r\n" -"invoked." +"takes them as arguments:" msgstr "" -#: src\idioms/rustdoc-init.md:77 -msgid "## Advantages\r" +#: src/idioms/rustdoc-init.md:58 +msgid "" +"/// Sends a request over the connection.\n" +" ///\n" +" /// # Example\n" +" /// ```\n" +" /// # fn call_send(connection: Connection, request: Request) {\n" +" /// let response = connection.send_request(request);\n" +" /// assert!(response.is_ok());\n" +" /// # }\n" +" /// ```\n" msgstr "" -#: src\idioms/rustdoc-init.md:79 -msgid "This is much more concise and avoids repetitive code in examples." +#: src/idioms/rustdoc-init.md:73 +msgid "" +"**Note** in the above example the line `assert!(response.is_ok());` will not " +"actually run while testing because it is inside a function which is never " +"invoked." msgstr "" -#: src\idioms/rustdoc-init.md:81 -msgid "## Disadvantages\r" +#: src/idioms/rustdoc-init.md:79 +msgid "This is much more concise and avoids repetitive code in examples." msgstr "" -#: src\idioms/rustdoc-init.md:83 +#: src/idioms/rustdoc-init.md:83 msgid "" "As example is in a function, the code will not be tested. Though it will " -"still be\r\n" -"checked to make sure it compiles when running a `cargo test`. So this " -"pattern is\r\n" -"most useful when you need `no_run`. With this, you do not need to add " -"`no_run`." -msgstr "" - -#: src\idioms/rustdoc-init.md:87 -msgid "## Discussion\r" +"still be checked to make sure it compiles when running a `cargo test`. So " +"this pattern is most useful when you need `no_run`. With this, you do not " +"need to add `no_run`." msgstr "" -#: src\idioms/rustdoc-init.md:89 +#: src/idioms/rustdoc-init.md:90 msgid "If assertions are not required this pattern works well." msgstr "" -#: src\idioms/rustdoc-init.md:91 +#: src/idioms/rustdoc-init.md:92 msgid "" "If they are, an alternative can be to create a public method to create a " -"helper\r\n" -"instance which is annotated with `#[doc(hidden)]` (so that users won't see " -"it).\r\n" -"Then this method can be called inside of rustdoc because it is part of " -"the\r\n" -"crate's public API." -msgstr "" - -#: src\idioms/temporary-mutability.md:1 -msgid "# Temporary mutability" +"helper instance which is annotated with `#[doc(hidden)]` (so that users " +"won't see it). Then this method can be called inside of rustdoc because it " +"is part of the crate's public API." msgstr "" -#: src\idioms/temporary-mutability.md:5 +#: src/idioms/temporary-mutability.md:5 msgid "" "Often it is necessary to prepare and process some data, but after that data " -"are\n" -"only inspected and never modified. The intention can be made explicit by " -"redefining\n" -"the mutable variable as immutable." +"are only inspected and never modified. The intention can be made explicit by " +"redefining the mutable variable as immutable." msgstr "" -#: src\idioms/temporary-mutability.md:9 +#: src/idioms/temporary-mutability.md:9 msgid "" "It can be done either by processing data within a nested block or by " -"redefining\n" -"the variable." +"redefining the variable." msgstr "" -#: src\idioms/temporary-mutability.md:14 +#: src/idioms/temporary-mutability.md:14 msgid "Say, vector must be sorted before usage." msgstr "" -#: src\idioms/temporary-mutability.md:16 +#: src/idioms/temporary-mutability.md:16 msgid "Using nested block:" msgstr "" -#: src\idioms/temporary-mutability.md:18 -msgid "" -"```rust,ignore\n" -"let data = {\n" -" let mut data = get_vec();\n" -" data.sort();\n" -" data\n" -"};\n" -"\n" -"// Here `data` is immutable.\n" -"```" +#: src/idioms/temporary-mutability.md:24 src/idioms/temporary-mutability.md:34 +msgid "// Here `data` is immutable.\n" msgstr "" -#: src\idioms/temporary-mutability.md:28 +#: src/idioms/temporary-mutability.md:28 msgid "Using variable rebinding:" msgstr "" -#: src\idioms/temporary-mutability.md:30 +#: src/idioms/temporary-mutability.md:40 msgid "" -"```rust,ignore\n" -"let mut data = get_vec();\n" -"data.sort();\n" -"let data = data;\n" -"\n" -"// Here `data` is immutable.\n" -"```" +"Compiler ensures that you don't accidentally mutate data after some point." msgstr "" -#: src\idioms/temporary-mutability.md:40 +#: src/idioms/temporary-mutability.md:44 msgid "" -"Compiler ensures that you don't accidentally mutate data after some point." +"Nested block requires additional indentation of block body. One more line to " +"return data from block or redefine variable." msgstr "" -#: src\idioms/temporary-mutability.md:44 +#: src/idioms/return-consumed-arg-on-error.md:1 +#, fuzzy +msgid "Return consumed argument on error" +msgstr "消費した引数をエラー時に返す" + +#: src/idioms/return-consumed-arg-on-error.md:5 msgid "" -"Nested block requires additional indentation of block body.\n" -"One more line to return data from block or redefine variable." +"If a fallible function consumes (moves) an argument, return that argument " +"back inside an error." msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:1 -msgid "# Return consumed argument on error" +#: src/idioms/return-consumed-arg-on-error.md:12 +msgid "\"using {value} in a meaningful way\"" msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:5 -msgid "" -"If a fallible function consumes (moves) an argument, return that argument " -"back inside\n" -"an error." -msgstr "" - -#: src\idioms/return-consumed-arg-on-error.md:10 -msgid "" -"```rust\n" -"pub fn send(value: String) -> Result<(), SendError> {\n" -" println!(\"using {value} in a meaningful way\");\n" -" // Simulate non-deterministic fallible action.\n" -" use std::time::SystemTime;\n" -" let period = " -"SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();\n" -" if period.subsec_nanos() % 2 == 1 {\n" -" Ok(())\n" -" } else {\n" -" Err(SendError(value))\n" -" }\n" -"}\n" -"\n" -"pub struct SendError(String);\n" -"\n" -"fn main() {\n" -" let mut value = \"imagine this is very long string\".to_string();\n" -"\n" -" let success = 's: {\n" -" // Try to send value two times.\n" -" for _ in 0..2 {\n" -" value = match send(value) {\n" -" Ok(()) => break 's true,\n" -" Err(SendError(value)) => value,\n" -" }\n" -" }\n" -" false\n" -" };\n" -"\n" -" println!(\"success: {}\", success);\n" -"}\n" -"```" +#: src/idioms/return-consumed-arg-on-error.md:13 +msgid "// Simulate non-deterministic fallible action.\n" +msgstr "" + +#: src/idioms/return-consumed-arg-on-error.md:28 +msgid "\"imagine this is very long string\"" msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:45 +#: src/idioms/return-consumed-arg-on-error.md:31 +msgid "// Try to send value two times.\n" +msgstr "" + +#: src/idioms/return-consumed-arg-on-error.md:41 +msgid "\"success: {success}\"" +msgstr "" + +#: src/idioms/return-consumed-arg-on-error.md:47 msgid "" -"In case of error you may want to try some alternative way or to\n" -"retry action in case of non-deterministic function. But if the argument\n" -"is always consumed, you are forced to clone it on every call, which\n" -"is not very efficient." +"In case of error you may want to try some alternative way or to retry action " +"in case of non-deterministic function. But if the argument is always " +"consumed, you are forced to clone it on every call, which is not very " +"efficient." msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:50 +#: src/idioms/return-consumed-arg-on-error.md:51 msgid "" -"The standard library uses this approach in e.g. `String::from_utf8` method.\n" -"When given a vector that doesn't contain valid UTF-8, a `FromUtf8Error`\n" -"is returned.\n" -"You can get original vector back using `FromUtf8Error::into_bytes` method." +"The standard library uses this approach in e.g. `String::from_utf8` method. " +"When given a vector that doesn't contain valid UTF-8, a `FromUtf8Error` is " +"returned. You can get original vector back using `FromUtf8Error::into_bytes` " +"method." msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:57 +#: src/idioms/return-consumed-arg-on-error.md:57 msgid "Better performance because of moving arguments whenever possible." msgstr "" -#: src\idioms/return-consumed-arg-on-error.md:61 +#: src/idioms/return-consumed-arg-on-error.md:61 msgid "Slightly more complex error types." msgstr "" -#: src\patterns/index.md:1 -msgid "# Design Patterns" -msgstr "" - -#: src\patterns/index.md:3 +#: src/patterns/index.md:3 msgid "" -"[Design patterns](https://en.wikipedia.org/wiki/Software_design_pattern) " -"are\n" -"\"general reusable solutions to a commonly occurring problem within a given\n" +"[Design patterns](https://en.wikipedia.org/wiki/Software_design_pattern) are " +"\"general reusable solutions to a commonly occurring problem within a given " "context in software design\". Design patterns are a great way to describe " -"the\n" -"culture of a programming language. Design patterns are very language-" -"specific -\n" -"what is a pattern in one language may be unnecessary in another due to a\n" -"language feature, or impossible to express due to a missing feature." +"the culture of a programming language. Design patterns are very language-" +"specific - what is a pattern in one language may be unnecessary in another " +"due to a language feature, or impossible to express due to a missing feature." msgstr "" -#: src\patterns/index.md:10 +#: src/patterns/index.md:10 msgid "" -"If overused, design patterns can add unnecessary complexity to programs.\n" +"If overused, design patterns can add unnecessary complexity to programs. " "However, they are a great way to share intermediate and advanced level " -"knowledge\n" -"about a programming language." +"knowledge about a programming language." msgstr "" -#: src\patterns/index.md:16 +#: src/patterns/index.md:16 msgid "" "Rust has many unique features. These features give us great benefit by " -"removing\n" -"whole classes of problems. Some of them are also patterns that are _unique_ " -"to Rust." +"removing whole classes of problems. Some of them are also patterns that are " +"_unique_ to Rust." msgstr "" -#: src\patterns/index.md:19 -msgid "## YAGNI" +#: src/patterns/index.md:20 +msgid "YAGNI" msgstr "" -#: src\patterns/index.md:21 +#: src/patterns/index.md:22 msgid "" -"YAGNI is an acronym that stands for `You Aren't Going to Need It`.\n" -"It's a vital software design principle to apply as you write code." +"YAGNI is an acronym that stands for `You Aren't Going to Need It`. It's a " +"vital software design principle to apply as you write code." msgstr "" -#: src\patterns/index.md:24 -msgid "> The best code I ever wrote was code I never wrote." +#: src/patterns/index.md:25 +msgid "The best code I ever wrote was code I never wrote." msgstr "" -#: src\patterns/index.md:26 +#: src/patterns/index.md:27 msgid "" "If we apply YAGNI to design patterns, we see that the features of Rust allow " -"us to\n" -"throw out many patterns. For instance, there is no need for the [strategy " -"pattern](https://en.wikipedia.org/wiki/Strategy_pattern)\n" -"in Rust because we can just use [traits](https://doc.rust-lang.org/book/" -"traits.html)." +"us to throw out many patterns. For instance, there is no need for the " +"[strategy pattern](https://en.wikipedia.org/wiki/Strategy_pattern) in Rust " +"because we can just use [traits](https://doc.rust-lang.org/book/traits.html)." msgstr "" -#: src\patterns/behavioural/intro.md:1 -msgid "# Behavioural Patterns" +#: src/patterns/behavioural/intro.md:1 +msgid "Behavioural Patterns" msgstr "" -#: src\patterns/behavioural/intro.md:3 +#: src/patterns/behavioural/intro.md:3 msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" msgstr "" -#: src\patterns/behavioural/intro.md:5 +#: src/patterns/behavioural/intro.md:5 msgid "" -"> Design patterns that identify common communication patterns among " -"objects.\n" -"> By doing so, these patterns increase flexibility in carrying out " +"Design patterns that identify common communication patterns among objects. " +"By doing so, these patterns increase flexibility in carrying out " "communication." msgstr "" -#: src\patterns/behavioural/command.md:1 -msgid "# Command" -msgstr "" - -#: src\patterns/behavioural/command.md:5 +#: src/patterns/behavioural/command.md:5 msgid "" "The basic idea of the Command pattern is to separate out actions into its " -"own\n" -"objects and pass them as parameters." +"own objects and pass them as parameters." msgstr "" -#: src\patterns/behavioural/command.md:10 +#: src/patterns/behavioural/command.md:10 msgid "" "Suppose we have a sequence of actions or transactions encapsulated as " -"objects.\n" -"We want these actions or commands to be executed or invoked in some order " -"later\n" -"at different time. These commands may also be triggered as a result of some " -"event.\n" -"For example, when a user pushes a button, or on arrival of a data packet.\n" -"In addition, these commands might be undoable. This may come in useful for\n" -"operations of an editor. We might want to store logs of executed commands so " -"that\n" -"we could reapply the changes later if the system crashes." -msgstr "" - -#: src\patterns/behavioural/command.md:20 -msgid "" -"Define two database operations `create table` and `add field`. Each of " -"these\n" +"objects. We want these actions or commands to be executed or invoked in some " +"order later at different time. These commands may also be triggered as a " +"result of some event. For example, when a user pushes a button, or on " +"arrival of a data packet. In addition, these commands might be undoable. " +"This may come in useful for operations of an editor. We might want to store " +"logs of executed commands so that we could reapply the changes later if the " +"system crashes." +msgstr "" + +#: src/patterns/behavioural/command.md:20 +msgid "" +"Define two database operations `create table` and `add field`. Each of these " "operations is a command which knows how to undo the command, e.g., `drop " -"table`\n" -"and `remove field`. When a user invokes a database migration operation then " -"each\n" -"command is executed in the defined order, and when the user invokes the " -"rollback\n" -"operation then the whole set of commands is invoked in reverse order." +"table` and `remove field`. When a user invokes a database migration " +"operation then each command is executed in the defined order, and when the " +"user invokes the rollback operation then the whole set of commands is " +"invoked in reverse order." msgstr "" -#: src\patterns/behavioural/command.md:26 -msgid "## Approach: Using trait objects" +#: src/patterns/behavioural/command.md:26 +msgid "Approach: Using trait objects" msgstr "" -#: src\patterns/behavioural/command.md:28 +#: src/patterns/behavioural/command.md:28 msgid "" -"We define a common trait which encapsulates our command with two operations\n" +"We define a common trait which encapsulates our command with two operations " "`execute` and `rollback`. All command `structs` must implement this trait." msgstr "" -#: src\patterns/behavioural/command.md:31 -msgid "" -"```rust\n" -"pub trait Migration {\n" -" fn execute(&self) -> &str;\n" -" fn rollback(&self) -> &str;\n" -"}\n" -"\n" -"pub struct CreateTable;\n" -"impl Migration for CreateTable {\n" -" fn execute(&self) -> &str {\n" -" \"create table\"\n" -" }\n" -" fn rollback(&self) -> &str {\n" -" \"drop table\"\n" -" }\n" -"}\n" -"\n" -"pub struct AddField;\n" -"impl Migration for AddField {\n" -" fn execute(&self) -> &str {\n" -" \"add field\"\n" -" }\n" -" fn rollback(&self) -> &str {\n" -" \"remove field\"\n" -" }\n" -"}\n" -"\n" -"struct Schema {\n" -" commands: Vec>,\n" -"}\n" -"\n" -"impl Schema {\n" -" fn new() -> Self {\n" -" Self { commands: vec![] }\n" -" }\n" -"\n" -" fn add_migration(&mut self, cmd: Box) {\n" -" self.commands.push(cmd);\n" -" }\n" -"\n" -" fn execute(&self) -> Vec<&str> {\n" -" self.commands.iter().map(|cmd| cmd.execute()).collect()\n" -" }\n" -" fn rollback(&self) -> Vec<&str> {\n" -" self.commands\n" -" .iter()\n" -" .rev() // reverse iterator's direction\n" -" .map(|cmd| cmd.rollback())\n" -" .collect()\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut schema = Schema::new();\n" -"\n" -" let cmd = Box::new(CreateTable);\n" -" schema.add_migration(cmd);\n" -" let cmd = Box::new(AddField);\n" -" schema.add_migration(cmd);\n" -"\n" -" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" -" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" -"}\n" -"```" +#: src/patterns/behavioural/command.md:40 +#: src/patterns/behavioural/command.md:90 +#: src/patterns/behavioural/command.md:143 +#: src/patterns/behavioural/command.md:145 +#: src/patterns/behavioural/command.md:196 +#: src/patterns/behavioural/command.md:198 +msgid "\"create table\"" msgstr "" -#: src\patterns/behavioural/command.md:95 -msgid "## Approach: Using function pointers" +#: src/patterns/behavioural/command.md:43 +#: src/patterns/behavioural/command.md:91 +#: src/patterns/behavioural/command.md:143 +#: src/patterns/behavioural/command.md:146 +#: src/patterns/behavioural/command.md:196 +#: src/patterns/behavioural/command.md:199 +msgid "\"drop table\"" msgstr "" -#: src\patterns/behavioural/command.md:97 -msgid "" -"We could follow another approach by creating each individual command as\n" -"a different function and store function pointers to invoke these functions " -"later\n" -"at a different time. Since function pointers implement all three traits " -"`Fn`,\n" -"`FnMut`, and `FnOnce` we could as well pass and store closures instead of\n" -"function pointers." +#: src/patterns/behavioural/command.md:50 +#: src/patterns/behavioural/command.md:90 +#: src/patterns/behavioural/command.md:134 +#: src/patterns/behavioural/command.md:145 +#: src/patterns/behavioural/command.md:187 +#: src/patterns/behavioural/command.md:198 +msgid "\"add field\"" msgstr "" -#: src\patterns/behavioural/command.md:103 -msgid "" -"```rust\n" -"type FnPtr = fn() -> String;\n" -"struct Command {\n" -" execute: FnPtr,\n" -" rollback: FnPtr,\n" -"}\n" -"\n" -"struct Schema {\n" -" commands: Vec,\n" -"}\n" -"\n" -"impl Schema {\n" -" fn new() -> Self {\n" -" Self { commands: vec![] }\n" -" }\n" -" fn add_migration(&mut self, execute: FnPtr, rollback: FnPtr) {\n" -" self.commands.push(Command { execute, rollback });\n" -" }\n" -" fn execute(&self) -> Vec {\n" -" self.commands.iter().map(|cmd| (cmd.execute)()).collect()\n" -" }\n" -" fn rollback(&self) -> Vec {\n" -" self.commands\n" -" .iter()\n" -" .rev()\n" -" .map(|cmd| (cmd.rollback)())\n" -" .collect()\n" -" }\n" -"}\n" -"\n" -"fn add_field() -> String {\n" -" \"add field\".to_string()\n" -"}\n" -"\n" -"fn remove_field() -> String {\n" -" \"remove field\".to_string()\n" -"}\n" -"\n" -"fn main() {\n" -" let mut schema = Schema::new();\n" -" schema.add_migration(|| \"create table\".to_string(), || \"drop " -"table\".to_string());\n" -" schema.add_migration(add_field, remove_field);\n" -" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" -" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" -"}\n" -"```" +#: src/patterns/behavioural/command.md:53 +#: src/patterns/behavioural/command.md:91 +#: src/patterns/behavioural/command.md:138 +#: src/patterns/behavioural/command.md:146 +#: src/patterns/behavioural/command.md:191 +#: src/patterns/behavioural/command.md:199 +msgid "\"remove field\"" +msgstr "" + +#: src/patterns/behavioural/command.md:76 +msgid "// reverse iterator's direction\n" msgstr "" -#: src\patterns/behavioural/command.md:150 -msgid "## Approach: Using `Fn` trait objects" +#: src/patterns/behavioural/command.md:95 +msgid "Approach: Using function pointers" msgstr "" -#: src\patterns/behavioural/command.md:152 +#: src/patterns/behavioural/command.md:97 msgid "" -"Finally, instead of defining a common command trait we could store\n" -"each command implementing the `Fn` trait separately in vectors." +"We could follow another approach by creating each individual command as a " +"different function and store function pointers to invoke these functions " +"later at a different time. Since function pointers implement all three " +"traits `Fn`, `FnMut`, and `FnOnce` we could as well pass and store closures " +"instead of function pointers." msgstr "" -#: src\patterns/behavioural/command.md:155 +#: src/patterns/behavioural/command.md:150 +msgid "Approach: Using `Fn` trait objects" +msgstr "" + +#: src/patterns/behavioural/command.md:152 msgid "" -"```rust\n" -"type Migration<'a> = Box &'a str>;\n" -"\n" -"struct Schema<'a> {\n" -" executes: Vec>,\n" -" rollbacks: Vec>,\n" -"}\n" -"\n" -"impl<'a> Schema<'a> {\n" -" fn new() -> Self {\n" -" Self {\n" -" executes: vec![],\n" -" rollbacks: vec![],\n" -" }\n" -" }\n" -" fn add_migration(&mut self, execute: E, rollback: R)\n" -" where\n" -" E: Fn() -> &'a str + 'static,\n" -" R: Fn() -> &'a str + 'static,\n" -" {\n" -" self.executes.push(Box::new(execute));\n" -" self.rollbacks.push(Box::new(rollback));\n" -" }\n" -" fn execute(&self) -> Vec<&str> {\n" -" self.executes.iter().map(|cmd| cmd()).collect()\n" -" }\n" -" fn rollback(&self) -> Vec<&str> {\n" -" self.rollbacks.iter().rev().map(|cmd| cmd()).collect()\n" -" }\n" -"}\n" -"\n" -"fn add_field() -> &'static str {\n" -" \"add field\"\n" -"}\n" -"\n" -"fn remove_field() -> &'static str {\n" -" \"remove field\"\n" -"}\n" -"\n" -"fn main() {\n" -" let mut schema = Schema::new();\n" -" schema.add_migration(|| \"create table\", || \"drop table\");\n" -" schema.add_migration(add_field, remove_field);\n" -" assert_eq!(vec![\"create table\", \"add field\"], schema.execute());\n" -" assert_eq!(vec![\"remove field\", \"drop table\"], schema.rollback());\n" -"}\n" -"```" +"Finally, instead of defining a common command trait we could store each " +"command implementing the `Fn` trait separately in vectors." msgstr "" -#: src\patterns/behavioural/command.md:205 +#: src/patterns/behavioural/command.md:205 msgid "" "If our commands are small and may be defined as functions or passed as a " -"closure\n" -"then using function pointers might be preferable since it does not exploit\n" -"dynamic dispatch. But if our command is a whole struct with a bunch of " -"functions\n" -"and variables defined as seperated module then using trait objects would be\n" -"more suitable. A case of application can be found in [`actix`](https://" -"actix.rs/),\n" -"which uses trait objects when it registers a handler function for routes.\n" -"In case of using `Fn` trait objects we can create and use commands in the " -"same\n" -"way as we used in case of function pointers." -msgstr "" - -#: src\patterns/behavioural/command.md:214 -msgid "" -"As performance, there is always a trade-off between performance and code\n" -"simplicity and organisation. Static dispatch gives faster performance, " -"while\n" -"dynamic dispatch provides flexibility when we structure our application." +"closure then using function pointers might be preferable since it does not " +"exploit dynamic dispatch. But if our command is a whole struct with a bunch " +"of functions and variables defined as separated module then using trait " +"objects would be more suitable. A case of application can be found in " +"[`actix`](https://actix.rs/), which uses trait objects when it registers a " +"handler function for routes. In case of using `Fn` trait objects we can " +"create and use commands in the same way as we used in case of function " +"pointers." msgstr "" -#: src\patterns/behavioural/command.md:220 +#: src/patterns/behavioural/command.md:214 msgid "" -"- [Command pattern](https://en.wikipedia.org/wiki/Command_pattern)\n" -"\n" -"- [Another example for the `command` pattern](https://web.archive.org/web/" -"20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" +"As performance, there is always a trade-off between performance and code " +"simplicity and organisation. Static dispatch gives faster performance, while " +"dynamic dispatch provides flexibility when we structure our application." msgstr "" -#: src\patterns/behavioural/interpreter.md:1 -msgid "# Interpreter" +#: src/patterns/behavioural/command.md:220 +msgid "[Command pattern](https://en.wikipedia.org/wiki/Command_pattern)" +msgstr "" + +#: src/patterns/behavioural/command.md:222 +msgid "" +"[Another example for the `command` pattern](https://web.archive.org/web/" +"20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" msgstr "" -#: src\patterns/behavioural/interpreter.md:5 +#: src/patterns/behavioural/interpreter.md:5 msgid "" "If a problem occurs very often and requires long and repetitive steps to " -"solve\n" -"it, then the problem instances might be expressed in a simple language and " -"an\n" -"interpreter object could solve it by interpreting the sentences written in " -"this\n" -"simple language." +"solve it, then the problem instances might be expressed in a simple language " +"and an interpreter object could solve it by interpreting the sentences " +"written in this simple language." msgstr "" -#: src\patterns/behavioural/interpreter.md:10 +#: src/patterns/behavioural/interpreter.md:10 msgid "Basically, for any kind of problems we define:" msgstr "" -#: src\patterns/behavioural/interpreter.md:12 +#: src/patterns/behavioural/interpreter.md:12 msgid "" -"- A [domain specific language](https://en.wikipedia.org/wiki/Domain-" -"specific_language),\n" -"- A grammar for this language,\n" -"- An interpreter that solves the problem instances." +"A [domain specific language](https://en.wikipedia.org/wiki/Domain-" +"specific_language)," msgstr "" -#: src\patterns/behavioural/interpreter.md:18 +#: src/patterns/behavioural/interpreter.md:14 +msgid "A grammar for this language," +msgstr "" + +#: src/patterns/behavioural/interpreter.md:15 +msgid "An interpreter that solves the problem instances." +msgstr "" + +#: src/patterns/behavioural/interpreter.md:19 msgid "" "Our goal is to translate simple mathematical expressions into postfix " -"expressions\n" -"(or [Reverse Polish notation](https://en.wikipedia.org/wiki/" -"Reverse_Polish_notation))\n" -"For simplicity, our expressions consist of ten digits `0`, ..., `9` and two\n" -"operations `+`, `-`. For example, the expression `2 + 4` is translated into\n" -"`2 4 +`." +"expressions (or [Reverse Polish notation](https://en.wikipedia.org/wiki/" +"Reverse_Polish_notation)) For simplicity, our expressions consist of ten " +"digits `0`, ..., `9` and two operations `+`, `-`. For example, the " +"expression `2 + 4` is translated into `2 4 +`." msgstr "" -#: src\patterns/behavioural/interpreter.md:24 -msgid "## Context Free Grammar for our problem" +#: src/patterns/behavioural/interpreter.md:26 +msgid "Context Free Grammar for our problem" msgstr "" -#: src\patterns/behavioural/interpreter.md:26 +#: src/patterns/behavioural/interpreter.md:28 msgid "" "Our task is translating infix expressions into postfix ones. Let's define a " -"context\n" -"free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-" -"`,\n" -"where:" +"context free grammar for a set of infix expressions over `0`, ..., `9`, `+`, " +"and `-`, where:" msgstr "" -#: src\patterns/behavioural/interpreter.md:30 -msgid "" -"- Terminal symbols: `0`, `...`, `9`, `+`, `-`\n" -"- Non-terminal symbols: `exp`, `term`\n" -"- Start symbol is `exp`\n" -"- And the following are production rules" +#: src/patterns/behavioural/interpreter.md:32 +msgid "Terminal symbols: `0`, `...`, `9`, `+`, `-`" msgstr "" -#: src\patterns/behavioural/interpreter.md:35 -msgid "" -"```ignore\n" -"exp -> exp + term\n" -"exp -> exp - term\n" -"exp -> term\n" -"term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n" -"```" +#: src/patterns/behavioural/interpreter.md:33 +msgid "Non-terminal symbols: `exp`, `term`" msgstr "" -#: src\patterns/behavioural/interpreter.md:42 +#: src/patterns/behavioural/interpreter.md:34 +msgid "Start symbol is `exp`" +msgstr "" + +#: src/patterns/behavioural/interpreter.md:35 +msgid "And the following are production rules" +msgstr "" + +#: src/patterns/behavioural/interpreter.md:44 msgid "" "**NOTE:** This grammar should be further transformed depending on what we " -"are going\n" -"to do with it. For example, we might need to remove left recursion. For " -"more\n" -"details please see [Compilers: Principles,Techniques, and Tools](https://" -"en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)\n" -"(aka Dragon Book)." +"are going to do with it. For example, we might need to remove left " +"recursion. For more details please see [Compilers: Principles,Techniques, " +"and Tools](https://en.wikipedia.org/wiki/" +"Compilers:_Principles,_Techniques,_and_Tools) (aka Dragon Book)." msgstr "" -#: src\patterns/behavioural/interpreter.md:47 -msgid "## Solution" -msgstr "" +#: src/patterns/behavioural/interpreter.md:50 +#, fuzzy +msgid "Solution" +msgstr "序文" -#: src\patterns/behavioural/interpreter.md:49 +#: src/patterns/behavioural/interpreter.md:52 msgid "" "We simply implement a recursive descent parser. For simplicity's sake, the " -"code\n" -"panics when an expression is syntactically wrong (for example `2-34` or `2+5-" -"`\n" -"are wrong according to the grammar definition)." +"code panics when an expression is syntactically wrong (for example `2-34` or " +"`2+5-` are wrong according to the grammar definition)." msgstr "" -#: src\patterns/behavioural/interpreter.md:53 -msgid "" -"```rust\n" -"pub struct Interpreter<'a> {\n" -" it: std::str::Chars<'a>,\n" -"}\n" -"\n" -"impl<'a> Interpreter<'a> {\n" -"\n" -" pub fn new(infix: &'a str) -> Self {\n" -" Self { it: infix.chars() }\n" -" }\n" -"\n" -" fn next_char(&mut self) -> Option {\n" -" self.it.next()\n" -" }\n" -"\n" -" pub fn interpret(&mut self, out: &mut String) {\n" -" self.term(out);\n" -"\n" -" while let Some(op) = self.next_char() {\n" -" if op == '+' || op == '-' {\n" -" self.term(out);\n" -" out.push(op);\n" -" } else {\n" -" panic!(\"Unexpected symbol '{}'\", op);\n" -" }\n" -" }\n" -" }\n" -"\n" -" fn term(&mut self, out: &mut String) {\n" -" match self.next_char() {\n" -" Some(ch) if ch.is_digit(10) => out.push(ch),\n" -" Some(ch) => panic!(\"Unexpected symbol '{}'\", ch),\n" -" None => panic!(\"Unexpected end of string\"),\n" -" }\n" -" }\n" -"}\n" -"\n" -"pub fn main() {\n" -" let mut intr = Interpreter::new(\"2+3\");\n" -" let mut postfix = String::new();\n" -" intr.interpret(&mut postfix);\n" -" assert_eq!(postfix, \"23+\");\n" -"\n" -" intr = Interpreter::new(\"1-2+3-4\");\n" -" postfix.clear();\n" -" intr.interpret(&mut postfix);\n" -" assert_eq!(postfix, \"12-3+4-\");\n" -"}\n" -"```" +#: src/patterns/behavioural/interpreter.md:74 +msgid "'+'" msgstr "" -#: src\patterns/behavioural/interpreter.md:105 -msgid "" -"There may be a wrong perception that the Interpreter design pattern is about " -"design\n" -"grammars for formal languages and implementation of parsers for these " -"grammars.\n" -"In fact, this pattern is about expressing problem instances in a more " -"specific\n" -"way and implementing functions/classes/structs that solve these problem " -"instances.\n" -"Rust language has `macro_rules!` that allow us to define special syntax and " -"rules\n" -"on how to expand this syntax into source code." -msgstr "" - -#: src\patterns/behavioural/interpreter.md:112 -msgid "" -"In the following example we create a simple `macro_rules!` that computes\n" -"[Euclidean length](https://en.wikipedia.org/wiki/Euclidean_distance) of `n`\n" -"dimensional vectors. Writing `norm!(x,1,2)` might be easier to express and " -"more\n" -"efficient than packing `x,1,2` into a `Vec` and calling a function " -"computing\n" -"the length." -msgstr "" - -#: src\patterns/behavioural/interpreter.md:118 -msgid "" -"```rust\n" -"macro_rules! norm {\n" -" ($($element:expr),*) => {\n" -" {\n" -" let mut n = 0.0;\n" -" $(\n" -" n += ($element as f64)*($element as f64);\n" -" )*\n" -" n.sqrt()\n" -" }\n" -" };\n" -"}\n" -"\n" -"fn main() {\n" -" let x = -3f64;\n" -" let y = 4f64;\n" -"\n" -" assert_eq!(3f64, norm!(x));\n" -" assert_eq!(5f64, norm!(x, y));\n" -" assert_eq!(0f64, norm!(0, 0, 0)); \n" -" assert_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5));\n" -"}\n" -"```" +#: src/patterns/behavioural/interpreter.md:74 +msgid "'-'" msgstr "" -#: src\patterns/behavioural/interpreter.md:144 -msgid "" -"- [Interpreter pattern](https://en.wikipedia.org/wiki/Interpreter_pattern)\n" -"- [Context free grammar](https://en.wikipedia.org/wiki/Context-" -"free_grammar)\n" -"- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" +#: src/patterns/behavioural/interpreter.md:78 +msgid "\"Unexpected symbol '{op}'\"" msgstr "" -#: src\patterns/behavioural/newtype.md:1 -msgid "# Newtype" +#: src/patterns/behavioural/interpreter.md:86 +msgid "\"Unexpected symbol '{ch}'\"" msgstr "" -#: src\patterns/behavioural/newtype.md:3 -msgid "" -"What if in some cases we want a type to behave similar to another type or\n" -"enforce some behaviour at compile time when using only type aliases would\n" -"not be enough?" +#: src/patterns/behavioural/interpreter.md:87 +msgid "\"Unexpected end of string\"" msgstr "" -#: src\patterns/behavioural/newtype.md:7 -msgid "" -"For example, if we want to create a custom `Display` implementation for " -"`String`\n" -"due to security considerations (e.g. passwords)." +#: src/patterns/behavioural/interpreter.md:93 +msgid "\"2+3\"" msgstr "" -#: src\patterns/behavioural/newtype.md:10 -msgid "" -"For such cases we could use the `Newtype` pattern to provide **type " -"safety**\n" -"and **encapsulation**." +#: src/patterns/behavioural/interpreter.md:96 +msgid "\"23+\"" msgstr "" -#: src\patterns/behavioural/newtype.md:15 -msgid "" -"Use a tuple struct with a single field to make an opaque wrapper for a " -"type.\n" -"This creates a new type, rather than an alias to a type (`type` items)." +#: src/patterns/behavioural/interpreter.md:98 +msgid "\"1-2+3-4\"" msgstr "" -#: src\patterns/behavioural/newtype.md:20 -msgid "" -"```rust,ignore\n" -"// Some type, not necessarily in the same module or even crate.\n" -"struct Foo {\n" -" //..\n" -"}\n" -"\n" -"impl Foo {\n" -" // These functions are not present on Bar.\n" -" //..\n" -"}\n" -"\n" -"// The newtype.\n" -"pub struct Bar(Foo);\n" -"\n" -"impl Bar {\n" -" // Constructor.\n" -" pub fn new(\n" -" //..\n" -" ) -> Self {\n" -"\n" -" //..\n" -"\n" -" }\n" -"\n" -" //..\n" -"}\n" -"\n" -"fn main() {\n" -" let b = Bar::new(...);\n" -"\n" -" // Foo and Bar are type incompatible, the following do not type check.\n" -" // let f: Foo = b;\n" -" // let b: Bar = Foo { ... };\n" -"}\n" -"```" +#: src/patterns/behavioural/interpreter.md:101 +msgid "\"12-3+4-\"" +msgstr "" + +#: src/patterns/behavioural/interpreter.md:107 +msgid "" +"There may be a wrong perception that the Interpreter design pattern is about " +"design grammars for formal languages and implementation of parsers for these " +"grammars. In fact, this pattern is about expressing problem instances in a " +"more specific way and implementing functions/classes/structs that solve " +"these problem instances. Rust language has `macro_rules!` that allow us to " +"define special syntax and rules on how to expand this syntax into source " +"code." +msgstr "" + +#: src/patterns/behavioural/interpreter.md:114 +msgid "" +"In the following example we create a simple `macro_rules!` that computes " +"[Euclidean length](https://en.wikipedia.org/wiki/Euclidean_distance) of `n` " +"dimensional vectors. Writing `norm!(x,1,2)` might be easier to express and " +"more efficient than packing `x,1,2` into a `Vec` and calling a function " +"computing the length." +msgstr "" + +#: src/patterns/behavioural/interpreter.md:146 +msgid "" +"[Interpreter pattern](https://en.wikipedia.org/wiki/Interpreter_pattern)" +msgstr "" + +#: src/patterns/behavioural/interpreter.md:147 +msgid "" +"[Context free grammar](https://en.wikipedia.org/wiki/Context-free_grammar)" +msgstr "" + +#: src/patterns/behavioural/interpreter.md:148 +msgid "[macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" +msgstr "" + +#: src/patterns/behavioural/newtype.md:3 +msgid "" +"What if in some cases we want a type to behave similar to another type or " +"enforce some behaviour at compile time when using only type aliases would " +"not be enough?" +msgstr "" + +#: src/patterns/behavioural/newtype.md:7 +msgid "" +"For example, if we want to create a custom `Display` implementation for " +"`String` due to security considerations (e.g. passwords)." +msgstr "" + +#: src/patterns/behavioural/newtype.md:10 +msgid "" +"For such cases we could use the `Newtype` pattern to provide **type safety** " +"and **encapsulation**." +msgstr "" + +#: src/patterns/behavioural/newtype.md:15 +msgid "" +"Use a tuple struct with a single field to make an opaque wrapper for a type. " +"This creates a new type, rather than an alias to a type (`type` items)." +msgstr "" + +#: src/patterns/behavioural/newtype.md:22 +msgid "// Create Newtype Password to override the Display trait for String\n" msgstr "" -#: src\patterns/behavioural/newtype.md:58 +#: src/patterns/behavioural/newtype.md:28 +msgid "\"****************\"" +msgstr "" + +#: src/patterns/behavioural/newtype.md:33 +msgid "\"ThisIsMyPassword\"" +msgstr "" + +#: src/patterns/behavioural/newtype.md:35 +msgid "\"unsecured_password: {unsecured_password}\"" +msgstr "" + +#: src/patterns/behavioural/newtype.md:36 +msgid "\"secured_password: {secured_password}\"" +msgstr "" + +#: src/patterns/behavioural/newtype.md:47 msgid "" -"The primary motivation for newtypes is abstraction. It allows you to share\n" +"The primary motivation for newtypes is abstraction. It allows you to share " "implementation details between types while precisely controlling the " -"interface.\n" -"By using a newtype rather than exposing the implementation type as part of " -"an\n" -"API, it allows you to change implementation backwards compatibly." +"interface. By using a newtype rather than exposing the implementation type " +"as part of an API, it allows you to change implementation backwards " +"compatibly." msgstr "" -#: src\patterns/behavioural/newtype.md:63 +#: src/patterns/behavioural/newtype.md:52 msgid "" -"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give\n" +"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give " "distinguishable `Miles` and `Kilometres`." msgstr "" -#: src\patterns/behavioural/newtype.md:68 +#: src/patterns/behavioural/newtype.md:57 msgid "" -"The wrapped and wrapper types are not type compatible (as opposed to using\n" +"The wrapped and wrapper types are not type compatible (as opposed to using " "`type`), so users of the newtype will never 'confuse' the wrapped and " -"wrapper\n" -"types." +"wrapper types." msgstr "" -#: src\patterns/behavioural/newtype.md:72 +#: src/patterns/behavioural/newtype.md:61 msgid "Newtypes are a zero-cost abstraction - there is no runtime overhead." msgstr "" -#: src\patterns/behavioural/newtype.md:74 +#: src/patterns/behavioural/newtype.md:63 msgid "" -"The privacy system ensures that users cannot access the wrapped type (if " -"the\n" +"The privacy system ensures that users cannot access the wrapped type (if the " "field is private, which it is by default)." msgstr "" -#: src\patterns/behavioural/newtype.md:79 +#: src/patterns/behavioural/newtype.md:68 msgid "" "The downside of newtypes (especially compared with type aliases), is that " -"there\n" -"is no special language support. This means there can be _a lot_ of " -"boilerplate.\n" -"You need a 'pass through' method for every method you want to expose on the\n" -"wrapped type, and an impl for every trait you want to also be implemented " -"for\n" -"the wrapper type." +"there is no special language support. This means there can be _a lot_ of " +"boilerplate. You need a 'pass through' method for every method you want to " +"expose on the wrapped type, and an impl for every trait you want to also be " +"implemented for the wrapper type." msgstr "" -#: src\patterns/behavioural/newtype.md:87 +#: src/patterns/behavioural/newtype.md:76 msgid "" "Newtypes are very common in Rust code. Abstraction or representing units are " -"the\n" -"most common uses, but they can be used for other reasons:" +"the most common uses, but they can be used for other reasons:" msgstr "" -#: src\patterns/behavioural/newtype.md:90 +#: src/patterns/behavioural/newtype.md:79 msgid "" -"- restricting functionality (reduce the functions exposed or traits " -"implemented),\n" -"- making a type with copy semantics have move semantics,\n" -"- abstraction by providing a more concrete type and thus hiding internal " -"types,\n" -" e.g.," +"restricting functionality (reduce the functions exposed or traits " +"implemented)," msgstr "" -#: src\patterns/behavioural/newtype.md:95 +#: src/patterns/behavioural/newtype.md:81 +msgid "making a type with copy semantics have move semantics," +msgstr "" + +#: src/patterns/behavioural/newtype.md:82 msgid "" -"```rust,ignore\n" -"pub struct Foo(Bar);\n" -"```" +"abstraction by providing a more concrete type and thus hiding internal " +"types, e.g.," msgstr "" -#: src\patterns/behavioural/newtype.md:99 +#: src/patterns/behavioural/newtype.md:89 msgid "" "Here, `Bar` might be some public, generic type and `T1` and `T2` are some " -"internal\n" -"types. Users of our module shouldn't know that we implement `Foo` by using a " -"`Bar`,\n" -"but what we're really hiding here is the types `T1` and `T2`, and how they " -"are used\n" -"with `Bar`." -msgstr "" - -#: src\patterns/behavioural/newtype.md:106 -msgid "" -"- [Advanced Types in the book](https://doc.rust-lang.org/book/ch19-04-" -"advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-" -"safety-and-abstraction)\n" -"- [Newtypes in Haskell](https://wiki.haskell.org/Newtype)\n" -"- [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-" -"types.html#creating-type-synonyms-with-type-aliases)\n" -"- [derive_more](https://crates.io/crates/derive_more), a crate for deriving " -"many\n" -" builtin traits on newtypes.\n" -"- [The Newtype Pattern In Rust](https://www.worthe-it.co.za/blog/2020-10-31-" -"newtype-pattern-in-rust.html)" -msgstr "" - -#: src\patterns/behavioural/RAII.md:1 -msgid "# RAII with guards" -msgstr "" - -#: src\patterns/behavioural/RAII.md:5 -msgid "" -"[RAII][wikipedia] stands for \"Resource Acquisition is Initialisation\" " -"which is a\n" -"terrible name. The essence of the pattern is that resource initialisation is " -"done\n" -"in the constructor of an object and finalisation in the destructor. This " -"pattern\n" -"is extended in Rust by using a RAII object as a guard of some resource and " -"relying\n" -"on the type system to ensure that access is always mediated by the guard " -"object." +"internal types. Users of our module shouldn't know that we implement `Foo` " +"by using a `Bar`, but what we're really hiding here is the types `T1` and " +"`T2`, and how they are used with `Bar`." +msgstr "" + +#: src/patterns/behavioural/newtype.md:96 +msgid "" +"[Advanced Types in the book](https://doc.rust-lang.org/book/ch19-04-advanced-" +"types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety-and-" +"abstraction)" +msgstr "" + +#: src/patterns/behavioural/newtype.md:97 +msgid "[Newtypes in Haskell](https://wiki.haskell.org/Newtype)" +msgstr "" + +#: src/patterns/behavioural/newtype.md:98 +msgid "" +"[Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-" +"types.html#creating-type-synonyms-with-type-aliases)" +msgstr "" + +#: src/patterns/behavioural/newtype.md:99 +msgid "" +"[derive_more](https://crates.io/crates/derive_more), a crate for deriving " +"many builtin traits on newtypes." +msgstr "" + +#: src/patterns/behavioural/newtype.md:101 +msgid "" +"[The Newtype Pattern In Rust](https://web.archive.org/web/20230519162111/" +"https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)" +msgstr "" + +#: src/patterns/behavioural/RAII.md:1 +msgid "RAII with guards" msgstr "" -#: src\patterns/behavioural/RAII.md:13 +#: src/patterns/behavioural/RAII.md:5 +msgid "" +"[RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) " +"stands for \"Resource Acquisition is Initialisation\" which is a terrible " +"name. The essence of the pattern is that resource initialisation is done in " +"the constructor of an object and finalisation in the destructor. This " +"pattern is extended in Rust by using a RAII object as a guard of some " +"resource and relying on the type system to ensure that access is always " +"mediated by the guard object." +msgstr "" + +#: src/patterns/behavioural/RAII.md:14 msgid "" "Mutex guards are the classic example of this pattern from the std library " -"(this\n" -"is a simplified version of the real implementation):" +"(this is a simplified version of the real implementation):" msgstr "" -#: src\patterns/behavioural/RAII.md:16 +#: src/patterns/behavioural/RAII.md:23 msgid "" -"```rust,ignore\n" -"use std::ops::Deref;\n" -"\n" -"struct Foo {}\n" -"\n" -"struct Mutex {\n" -" // We keep a reference to our data: T here.\n" -" //..\n" -"}\n" -"\n" -"struct MutexGuard<'a, T: 'a> {\n" -" data: &'a T,\n" +"// We keep a reference to our data: T here.\n" " //..\n" -"}\n" -"\n" -"// Locking the mutex is explicit.\n" -"impl Mutex {\n" -" fn lock(&self) -> MutexGuard {\n" -" // Lock the underlying OS mutex.\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:31 +msgid "// Locking the mutex is explicit.\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:35 +msgid "" +"// Lock the underlying OS mutex.\n" " //..\n" -"\n" -" // MutexGuard keeps a reference to self\n" -" MutexGuard {\n" -" data: self,\n" -" //..\n" -" }\n" -" }\n" -"}\n" -"\n" -"// Destructor for unlocking the mutex.\n" -"impl<'a, T> Drop for MutexGuard<'a, T> {\n" -" fn drop(&mut self) {\n" -" // Unlock the underlying OS mutex.\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:38 +msgid "// MutexGuard keeps a reference to self\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:45 +msgid "// Destructor for unlocking the mutex.\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:49 +msgid "" +"// Unlock the underlying OS mutex.\n" " //..\n" -" }\n" -"}\n" -"\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:53 +msgid "" "// Implementing Deref means we can treat MutexGuard like a pointer to T.\n" -"impl<'a, T> Deref for MutexGuard<'a, T> {\n" -" type Target = T;\n" -"\n" -" fn deref(&self) -> &T {\n" -" self.data\n" -" }\n" -"}\n" -"\n" -"fn baz(x: Mutex) {\n" -" let xx = x.lock();\n" -" xx.foo(); // foo is a method on Foo.\n" -" // The borrow checker ensures we can't store a reference to the " -"underlying\n" -" // Foo which will outlive the guard xx.\n" -"\n" -" // x is unlocked when we exit this function and xx's destructor is " +msgstr "" + +#: src/patterns/behavioural/RAII.md:65 +msgid "" +"// foo is a method on Foo.\n" +" // The borrow checker ensures we can't store a reference to " +"the underlying\n" +" // Foo which will outlive the guard xx.\n" +msgstr "" + +#: src/patterns/behavioural/RAII.md:69 +msgid "" +"// x is unlocked when we exit this function and xx's destructor is " "executed.\n" -"}\n" -"```" msgstr "" -#: src\patterns/behavioural/RAII.md:74 +#: src/patterns/behavioural/RAII.md:75 msgid "" -"Where a resource must be finalised after use, RAII can be used to do this\n" +"Where a resource must be finalised after use, RAII can be used to do this " "finalisation. If it is an error to access that resource after finalisation, " -"then\n" -"this pattern can be used to prevent such errors." +"then this pattern can be used to prevent such errors." msgstr "" -#: src\patterns/behavioural/RAII.md:80 +#: src/patterns/behavioural/RAII.md:81 msgid "" "Prevents errors where a resource is not finalised and where a resource is " -"used\n" -"after finalisation." +"used after finalisation." msgstr "" -#: src\patterns/behavioural/RAII.md:85 +#: src/patterns/behavioural/RAII.md:86 msgid "" -"RAII is a useful pattern for ensuring resources are properly deallocated or\n" +"RAII is a useful pattern for ensuring resources are properly deallocated or " "finalised. We can make use of the borrow checker in Rust to statically " -"prevent\n" -"errors stemming from using resources after finalisation takes place." +"prevent errors stemming from using resources after finalisation takes place." msgstr "" -#: src\patterns/behavioural/RAII.md:89 +#: src/patterns/behavioural/RAII.md:90 msgid "" "The core aim of the borrow checker is to ensure that references to data do " -"not\n" -"outlive that data. The RAII guard pattern works because the guard object\n" -"contains a reference to the underlying resource and only exposes such\n" +"not outlive that data. The RAII guard pattern works because the guard object " +"contains a reference to the underlying resource and only exposes such " "references. Rust ensures that the guard cannot outlive the underlying " -"resource\n" -"and that references to the resource mediated by the guard cannot outlive " -"the\n" -"guard. To see how this works it is helpful to examine the signature of " -"`deref`\n" -"without lifetime elision:" +"resource and that references to the resource mediated by the guard cannot " +"outlive the guard. To see how this works it is helpful to examine the " +"signature of `deref` without lifetime elision:" msgstr "" -#: src\patterns/behavioural/RAII.md:97 -msgid "" -"```rust,ignore\n" -"fn deref<'a>(&'a self) -> &'a T {\n" -" //..\n" -"}\n" -"```" -msgstr "" - -#: src\patterns/behavioural/RAII.md:103 +#: src/patterns/behavioural/RAII.md:104 msgid "" "The returned reference to the resource has the same lifetime as `self` " -"(`'a`).\n" -"The borrow checker therefore ensures that the lifetime of the reference to " -"`T`\n" -"is shorter than the lifetime of `self`." +"(`'a`). The borrow checker therefore ensures that the lifetime of the " +"reference to `T` is shorter than the lifetime of `self`." msgstr "" -#: src\patterns/behavioural/RAII.md:107 +#: src/patterns/behavioural/RAII.md:108 msgid "" "Note that implementing `Deref` is not a core part of this pattern, it only " -"makes\n" -"using the guard object more ergonomic. Implementing a `get` method on the " -"guard\n" -"works just as well." +"makes using the guard object more ergonomic. Implementing a `get` method on " +"the guard works just as well." msgstr "" -#: src\patterns/behavioural/RAII.md:113 +#: src/patterns/behavioural/RAII.md:114 msgid "[Finalisation in destructors idiom](../../idioms/dtor-finally.md)" msgstr "" -#: src\patterns/behavioural/RAII.md:115 +#: src/patterns/behavioural/RAII.md:116 msgid "" "RAII is a common pattern in C++: [cppreference.com](http://" -"en.cppreference.com/w/cpp/language/raii),\n" -"[wikipedia][wikipedia]." +"en.cppreference.com/w/cpp/language/raii), [wikipedia](https://" +"en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)." msgstr "" -#: src\patterns/behavioural/RAII.md:120 +#: src/patterns/behavioural/RAII.md:122 msgid "" "[Style guide entry](https://doc.rust-lang.org/1.0.0/style/ownership/" -"raii.html)\n" -"(currently just a placeholder)." +"raii.html) (currently just a placeholder)." msgstr "" -#: src\patterns/behavioural/strategy.md:1 -msgid "# Strategy (aka Policy)" +#: src/patterns/behavioural/strategy.md:1 +msgid "Strategy (aka Policy)" msgstr "" -#: src\patterns/behavioural/strategy.md:5 +#: src/patterns/behavioural/strategy.md:5 msgid "" "The [Strategy design pattern](https://en.wikipedia.org/wiki/" -"Strategy_pattern)\n" -"is a technique that enables separation of concerns.\n" -"It also allows to decouple software modules through [Dependency Inversion]" +"Strategy_pattern) is a technique that enables separation of concerns. It " +"also allows to decouple software modules through [Dependency Inversion]" "(https://en.wikipedia.org/wiki/Dependency_inversion_principle)." msgstr "" -#: src\patterns/behavioural/strategy.md:9 +#: src/patterns/behavioural/strategy.md:10 msgid "" "The basic idea behind the Strategy pattern is that, given an algorithm " -"solving\n" -"a particular problem, we define only the skeleton of the algorithm at an " -"abstract\n" -"level, and we separate the specific algorithm’s implementation into " -"different parts." +"solving a particular problem, we define only the skeleton of the algorithm " +"at an abstract level, and we separate the specific algorithm’s " +"implementation into different parts." msgstr "" -#: src\patterns/behavioural/strategy.md:13 +#: src/patterns/behavioural/strategy.md:15 msgid "" "In this way, a client using the algorithm may choose a specific " -"implementation,\n" -"while the general algorithm workflow remains the same. In other words, the " -"abstract\n" -"specification of the class does not depend on the specific implementation of " -"the\n" -"derived class, but specific implementation must adhere to the abstract " -"specification.\n" -"This is why we call it \"Dependency Inversion\"." -msgstr "" - -#: src\patterns/behavioural/strategy.md:21 -msgid "" -"Imagine we are working on a project that generates reports every month.\n" -"We need the reports to be generated in different formats (strategies), " -"e.g.,\n" -"in `JSON` or `Plain Text` formats.\n" -"But things vary over time, and we don't know what kind of requirement we may " -"get\n" -"in the future. For example, we may need to generate our report in a " -"completely new\n" -"format, or just modify one of the existing formats." -msgstr "" - -#: src\patterns/behavioural/strategy.md:30 -msgid "" -"In this example our invariants (or abstractions) are `Context`, " -"`Formatter`,\n" -"and `Report`, while `Text` and `Json` are our strategy structs. These " -"strategies\n" +"implementation, while the general algorithm workflow remains the same. In " +"other words, the abstract specification of the class does not depend on the " +"specific implementation of the derived class, but specific implementation " +"must adhere to the abstract specification. This is why we call it " +"\"Dependency Inversion\"." +msgstr "" + +#: src/patterns/behavioural/strategy.md:23 +msgid "" +"Imagine we are working on a project that generates reports every month. We " +"need the reports to be generated in different formats (strategies), e.g., in " +"`JSON` or `Plain Text` formats. But things vary over time, and we don't know " +"what kind of requirement we may get in the future. For example, we may need " +"to generate our report in a completely new format, or just modify one of the " +"existing formats." +msgstr "" + +#: src/patterns/behavioural/strategy.md:32 +msgid "" +"In this example our invariants (or abstractions) are `Formatter` and " +"`Report`, while `Text` and `Json` are our strategy structs. These strategies " "have to implement the `Formatter` trait." msgstr "" -#: src\patterns/behavioural/strategy.md:34 +#: src/patterns/behavioural/strategy.md:48 msgid "" -"```rust\n" -"use std::collections::HashMap;\n" -"\n" -"type Data = HashMap;\n" -"\n" -"trait Formatter {\n" -" fn format(&self, data: &Data, buf: &mut String);\n" -"}\n" -"\n" -"struct Report;\n" -"\n" -"impl Report {\n" -" // Write should be used but we kept it as String to ignore error " -"handling\n" -" fn generate(g: T, s: &mut String) {\n" -" // backend operations...\n" -" let mut data = HashMap::new();\n" -" data.insert(\"one\".to_string(), 1);\n" -" data.insert(\"two\".to_string(), 2);\n" -" // generate report\n" -" g.format(&data, s);\n" -" }\n" -"}\n" -"\n" -"struct Text;\n" -"impl Formatter for Text {\n" -" fn format(&self, data: &Data, buf: &mut String) {\n" -" for (k, v) in data {\n" -" let entry = format!(\"{} {}\\n\", k, v);\n" -" buf.push_str(&entry);\n" -" }\n" -" }\n" -"}\n" -"\n" -"struct Json;\n" -"impl Formatter for Json {\n" -" fn format(&self, data: &Data, buf: &mut String) {\n" -" buf.push('[');\n" -" for (k, v) in data.into_iter() {\n" -" let entry = format!(r#\"{{\"{}\":\"{}\"}}\"#, k, v);\n" -" buf.push_str(&entry);\n" -" buf.push(',');\n" -" }\n" -" if !data.is_empty() {\n" -" buf.pop(); // remove extra , at the end\n" -" }\n" -" buf.push(']');\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut s = String::from(\"\");\n" -" Report::generate(Text, &mut s);\n" -" assert!(s.contains(\"one 1\"));\n" -" assert!(s.contains(\"two 2\"));\n" -"\n" -" s.clear(); // reuse the same buffer\n" -" Report::generate(Json, &mut s);\n" -" assert!(s.contains(r#\"{\"one\":\"1\"}\"#));\n" -" assert!(s.contains(r#\"{\"two\":\"2\"}\"#));\n" -"}\n" -"```" +"// Write should be used but we kept it as String to ignore error handling\n" +msgstr "" + +#: src/patterns/behavioural/strategy.md:50 +msgid "// backend operations...\n" +msgstr "" + +#: src/patterns/behavioural/strategy.md:52 +msgid "\"one\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:53 +msgid "\"two\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:54 +msgid "// generate report\n" +msgstr "" + +#: src/patterns/behavioural/strategy.md:63 +msgid "\"{k} {v}\\n\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:72 +msgid "'['" +msgstr "" + +#: src/patterns/behavioural/strategy.md:74 +msgid "r#\"{{\"{}\":\"{}\"}}\"#" +msgstr "" + +#: src/patterns/behavioural/strategy.md:76 +msgid "','" +msgstr "" + +#: src/patterns/behavioural/strategy.md:79 +msgid "// remove extra , at the end\n" +msgstr "" + +#: src/patterns/behavioural/strategy.md:81 +msgid "']'" +msgstr "" + +#: src/patterns/behavioural/strategy.md:86 +msgid "\"\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:88 +msgid "\"one 1\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:89 +msgid "\"two 2\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:91 +msgid "// reuse the same buffer\n" msgstr "" -#: src\patterns/behavioural/strategy.md:98 +#: src/patterns/behavioural/strategy.md:93 +msgid "r#\"{\"one\":\"1\"}\"#" +msgstr "" + +#: src/patterns/behavioural/strategy.md:94 +msgid "r#\"{\"two\":\"2\"}\"#" +msgstr "" + +#: src/patterns/behavioural/strategy.md:100 msgid "" "The main advantage is separation of concerns. For example, in this case " -"`Report`\n" -"does not know anything about specific implementations of `Json` and `Text`,\n" -"whereas the output implementations does not care about how data is " -"preprocessed,\n" -"stored, and fetched. The only thing they have to know is context and a " -"specific\n" -"trait and method to implement, i.e,`Formatter` and `run`." +"`Report` does not know anything about specific implementations of `Json` and " +"`Text`, whereas the output implementations does not care about how data is " +"preprocessed, stored, and fetched. The only thing they have to know is a " +"specific trait to implement and its method defining the concrete algorithm " +"implementation processing the result, i.e., `Formatter` and `format(...)`." msgstr "" -#: src\patterns/behavioural/strategy.md:106 +#: src/patterns/behavioural/strategy.md:109 msgid "" "For each strategy there must be implemented at least one module, so number " -"of modules\n" -"increases with number of strategies. If there are many strategies to choose " -"from\n" -"then users have to know how strategies differ from one another." +"of modules increases with number of strategies. If there are many strategies " +"to choose from then users have to know how strategies differ from one " +"another." msgstr "" -#: src\patterns/behavioural/strategy.md:112 +#: src/patterns/behavioural/strategy.md:115 msgid "" -"In the previous example all strategies are implemented in a single file.\n" +"In the previous example all strategies are implemented in a single file. " "Ways of providing different strategies includes:" msgstr "" -#: src\patterns/behavioural/strategy.md:115 +#: src/patterns/behavioural/strategy.md:118 msgid "" -"- All in one file (as shown in this example, similar to being separated as " -"modules)\n" -"- Separated as modules, E.g. `formatter::json` module, `formatter::text` " -"module\n" -"- Use compiler feature flags, E.g. `json` feature, `text` feature\n" -"- Separated as crates, E.g. `json` crate, `text` crate" +"All in one file (as shown in this example, similar to being separated as " +"modules)" +msgstr "" + +#: src/patterns/behavioural/strategy.md:120 +msgid "" +"Separated as modules, E.g. `formatter::json` module, `formatter::text` module" +msgstr "" + +#: src/patterns/behavioural/strategy.md:121 +msgid "Use compiler feature flags, E.g. `json` feature, `text` feature" +msgstr "" + +#: src/patterns/behavioural/strategy.md:122 +msgid "Separated as crates, E.g. `json` crate, `text` crate" msgstr "" -#: src\patterns/behavioural/strategy.md:120 +#: src/patterns/behavioural/strategy.md:124 msgid "" "Serde crate is a good example of the `Strategy` pattern in action. Serde " -"allows\n" -"[full customization](https://serde.rs/custom-serialization.html) of the " -"serialization\n" -"behavior by manually implementing `Serialize` and `Deserialize` traits for " -"our\n" -"type. For example, we could easily swap `serde_json` with `serde_cbor` since " -"they\n" -"expose similar methods. Having this makes the helper crate `serde_transcode` " -"much\n" -"more useful and ergonomic." +"allows [full customization](https://serde.rs/custom-serialization.html) of " +"the serialization behavior by manually implementing `Serialize` and " +"`Deserialize` traits for our type. For example, we could easily swap " +"`serde_json` with `serde_cbor` since they expose similar methods. Having " +"this makes the helper crate `serde_transcode` much more useful and ergonomic." msgstr "" -#: src\patterns/behavioural/strategy.md:127 +#: src/patterns/behavioural/strategy.md:131 msgid "" "However, we don't need to use traits in order to design this pattern in Rust." msgstr "" -#: src\patterns/behavioural/strategy.md:129 +#: src/patterns/behavioural/strategy.md:133 msgid "" "The following toy example demonstrates the idea of the Strategy pattern " -"using Rust\n" -"`closures`:" -msgstr "" - -#: src\patterns/behavioural/strategy.md:132 -msgid "" -"```rust\n" -"struct Adder;\n" -"impl Adder {\n" -" pub fn add(x: u8, y: u8, f: F) -> u8\n" -" where\n" -" F: Fn(u8, u8) -> u8,\n" -" {\n" -" f(x, y)\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let arith_adder = |x, y| x + y;\n" -" let bool_adder = |x, y| {\n" -" if x == 1 || y == 1 {\n" -" 1\n" -" } else {\n" -" 0\n" -" }\n" -" };\n" -" let custom_adder = |x, y| 2 * x + y;\n" -"\n" -" assert_eq!(9, Adder::add(4, 5, arith_adder));\n" -" assert_eq!(0, Adder::add(0, 0, bool_adder));\n" -" assert_eq!(5, Adder::add(1, 3, custom_adder));\n" -"}\n" -"```" +"using Rust `closures`:" msgstr "" -#: src\patterns/behavioural/strategy.md:160 +#: src/patterns/behavioural/strategy.md:164 msgid "In fact, Rust already uses this idea for `Options`'s `map` method:" msgstr "" -#: src\patterns/behavioural/strategy.md:162 +#: src/patterns/behavioural/strategy.md:168 +msgid "\"Rust\"" +msgstr "" + +#: src/patterns/behavioural/strategy.md:180 +msgid "[Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern)" +msgstr "" + +#: src/patterns/behavioural/strategy.md:181 msgid "" -"```rust\n" -"fn main() {\n" -" let val = Some(\"Rust\");\n" -"\n" -" let len_strategy = |s: &str| s.len();\n" -" assert_eq!(4, val.map(len_strategy).unwrap());\n" -"\n" -" let first_byte_strategy = |s: &str| s.bytes().next().unwrap();\n" -" assert_eq!(82, val.map(first_byte_strategy).unwrap());\n" -"}\n" -"```" +"[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection)" msgstr "" -#: src\patterns/behavioural/strategy.md:176 +#: src/patterns/behavioural/strategy.md:182 msgid "" -"- [Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern)\n" -"- [Dependency Injection](https://en.wikipedia.org/wiki/" -"Dependency_injection)\n" -"- [Policy Based Design](https://en.wikipedia.org/wiki/Modern_C+" -"+_Design#Policy-based_design)" +"[Policy Based Design](https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-" +"based_design)" msgstr "" -#: src\patterns/behavioural/visitor.md:1 -msgid "# Visitor" +#: src/patterns/behavioural/strategy.md:183 +msgid "" +"[Implementing a TCP server for Space Applications in Rust using the Strategy " +"Pattern](https://web.archive.org/web/20231003171500/https://robamu.github.io/" +"posts/rust-strategy-pattern/)" msgstr "" -#: src\patterns/behavioural/visitor.md:5 +#: src/patterns/behavioural/visitor.md:5 msgid "" -"A visitor encapsulates an algorithm that operates over a heterogeneous\n" -"collection of objects. It allows multiple different algorithms to be " -"written\n" -"over the same data without having to modify the data (or their primary\n" +"A visitor encapsulates an algorithm that operates over a heterogeneous " +"collection of objects. It allows multiple different algorithms to be written " +"over the same data without having to modify the data (or their primary " "behaviour)." msgstr "" -#: src\patterns/behavioural/visitor.md:10 +#: src/patterns/behavioural/visitor.md:10 msgid "" -"Furthermore, the visitor pattern allows separating the traversal of\n" -"a collection of objects from the operations performed on each object." +"Furthermore, the visitor pattern allows separating the traversal of a " +"collection of objects from the operations performed on each object." +msgstr "" + +#: src/patterns/behavioural/visitor.md:16 +msgid "// The data we will visit\n" msgstr "" -#: src\patterns/behavioural/visitor.md:15 +#: src/patterns/behavioural/visitor.md:33 +msgid "// The abstract visitor\n" +msgstr "" + +#: src/patterns/behavioural/visitor.md:47 msgid "" -"```rust,ignore\n" -"// The data we will visit\n" -"mod ast {\n" -" pub enum Stmt {\n" -" Expr(Expr),\n" -" Let(Name, Expr),\n" -" }\n" -"\n" -" pub struct Name {\n" -" value: String,\n" -" }\n" -"\n" -" pub enum Expr {\n" -" IntLit(i64),\n" -" Add(Box, Box),\n" -" Sub(Box, Box),\n" -" }\n" -"}\n" -"\n" -"// The abstract visitor\n" -"mod visit {\n" -" use ast::*;\n" -"\n" -" pub trait Visitor {\n" -" fn visit_name(&mut self, n: &Name) -> T;\n" -" fn visit_stmt(&mut self, s: &Stmt) -> T;\n" -" fn visit_expr(&mut self, e: &Expr) -> T;\n" -" }\n" -"}\n" -"\n" -"use visit::*;\n" -"use ast::*;\n" -"\n" "// An example concrete implementation - walks the AST interpreting it as " "code.\n" -"struct Interpreter;\n" -"impl Visitor for Interpreter {\n" -" fn visit_name(&mut self, n: &Name) -> i64 { panic!() }\n" -" fn visit_stmt(&mut self, s: &Stmt) -> i64 {\n" -" match *s {\n" -" Stmt::Expr(ref e) => self.visit_expr(e),\n" -" Stmt::Let(..) => unimplemented!(),\n" -" }\n" -" }\n" -"\n" -" fn visit_expr(&mut self, e: &Expr) -> i64 {\n" -" match *e {\n" -" Expr::IntLit(n) => n,\n" -" Expr::Add(ref lhs, ref rhs) => self.visit_expr(lhs) + " -"self.visit_expr(rhs),\n" -" Expr::Sub(ref lhs, ref rhs) => self.visit_expr(lhs) - " -"self.visit_expr(rhs),\n" -" }\n" -" }\n" -"}\n" -"```" msgstr "" -#: src\patterns/behavioural/visitor.md:69 +#: src/patterns/behavioural/visitor.md:71 msgid "" "One could implement further visitors, for example a type checker, without " -"having\n" -"to modify the AST data." +"having to modify the AST data." msgstr "" -#: src\patterns/behavioural/visitor.md:74 +#: src/patterns/behavioural/visitor.md:76 msgid "" "The visitor pattern is useful anywhere that you want to apply an algorithm " -"to\n" -"heterogeneous data. If data is homogeneous, you can use an iterator-like " -"pattern.\n" -"Using a visitor object (rather than a functional approach) allows the " -"visitor to\n" -"be stateful and thus communicate information between nodes." +"to heterogeneous data. If data is homogeneous, you can use an iterator-like " +"pattern. Using a visitor object (rather than a functional approach) allows " +"the visitor to be stateful and thus communicate information between nodes." msgstr "" -#: src\patterns/behavioural/visitor.md:81 +#: src/patterns/behavioural/visitor.md:83 msgid "" -"It is common for the `visit_*` methods to return void (as opposed to in the\n" +"It is common for the `visit_*` methods to return void (as opposed to in the " "example). In that case it is possible to factor out the traversal code and " -"share\n" -"it between algorithms (and also to provide noop default methods). In Rust, " -"the\n" -"common way to do this is to provide `walk_*` functions for each datum. For\n" -"example," -msgstr "" - -#: src\patterns/behavioural/visitor.md:87 -msgid "" -"```rust,ignore\n" -"pub fn walk_expr(visitor: &mut Visitor, e: &Expr) {\n" -" match *e {\n" -" Expr::IntLit(_) => {},\n" -" Expr::Add(ref lhs, ref rhs) => {\n" -" visitor.visit_expr(lhs);\n" -" visitor.visit_expr(rhs);\n" -" }\n" -" Expr::Sub(ref lhs, ref rhs) => {\n" -" visitor.visit_expr(lhs);\n" -" visitor.visit_expr(rhs);\n" -" }\n" -" }\n" -"}\n" -"```" +"share it between algorithms (and also to provide noop default methods). In " +"Rust, the common way to do this is to provide `walk_*` functions for each " +"datum. For example," msgstr "" -#: src\patterns/behavioural/visitor.md:103 +#: src/patterns/behavioural/visitor.md:105 msgid "" "In other languages (e.g., Java) it is common for data to have an `accept` " -"method\n" -"which performs the same duty." +"method which performs the same duty." msgstr "" -#: src\patterns/behavioural/visitor.md:108 +#: src/patterns/behavioural/visitor.md:110 msgid "The visitor pattern is a common pattern in most OO languages." msgstr "" -#: src\patterns/behavioural/visitor.md:110 +#: src/patterns/behavioural/visitor.md:112 msgid "[Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern)" msgstr "" -#: src\patterns/behavioural/visitor.md:112 +#: src/patterns/behavioural/visitor.md:114 msgid "" -"The [fold](../creational/fold.md) pattern is similar to visitor but " -"produces\n" +"The [fold](../creational/fold.md) pattern is similar to visitor but produces " "a new version of the visited data structure." msgstr "" -#: src\patterns/creational/intro.md:1 -msgid "# Creational Patterns" +#: src/patterns/creational/intro.md:1 +msgid "Creational Patterns" msgstr "" -#: src\patterns/creational/intro.md:3 +#: src/patterns/creational/intro.md:3 msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" msgstr "" -#: src\patterns/creational/intro.md:5 +#: src/patterns/creational/intro.md:5 msgid "" -"> Design patterns that deal with object creation mechanisms, trying to " -"create objects\n" -"> in a manner suitable to the situation. The basic form of object creation " -"could\n" -"> result in design problems or in added complexity to the design. Creational " -"design\n" -"> patterns solve this problem by somehow controlling this object creation." +"Design patterns that deal with object creation mechanisms, trying to create " +"objects in a manner suitable to the situation. The basic form of object " +"creation could result in design problems or in added complexity to the " +"design. Creational design patterns solve this problem by somehow controlling " +"this object creation." +msgstr "" + +#: src/patterns/creational/builder.md:5 +msgid "Construct an object with calls to a builder helper." msgstr "" -#: src\patterns/creational/builder.md:1 -msgid "# Builder" +#: src/patterns/creational/builder.md:12 +msgid "// Lots of complicated fields.\n" msgstr "" -#: src\patterns/creational/builder.md:5 -msgid "Construct an object with calls to a builder helper." +#: src/patterns/creational/builder.md:17 +msgid "// This method will help users to discover the builder\n" +msgstr "" + +#: src/patterns/creational/builder.md:25 +msgid "// Probably lots of optional fields.\n" +msgstr "" + +#: src/patterns/creational/builder.md:31 +msgid "// Set the minimally required fields of Foo.\n" +msgstr "" + +#: src/patterns/creational/builder.md:33 +msgid "\"X\"" msgstr "" -#: src\patterns/creational/builder.md:9 +#: src/patterns/creational/builder.md:38 msgid "" -"```rust\n" -"#[derive(Debug, PartialEq)]\n" -"pub struct Foo {\n" -" // Lots of complicated fields.\n" -" bar: String,\n" -"}\n" -"\n" -"impl Foo {\n" -" // This method will help users to discover the builder\n" -" pub fn builder() -> FooBuilder {\n" -" FooBuilder::default()\n" -" }\n" -"}\n" -"\n" -"#[derive(Default)]\n" -"pub struct FooBuilder {\n" -" // Probably lots of optional fields.\n" -" bar: String,\n" -"}\n" -"\n" -"impl FooBuilder {\n" -" pub fn new(/* ... */) -> FooBuilder {\n" -" // Set the minimally required fields of Foo.\n" -" FooBuilder {\n" -" bar: String::from(\"X\"),\n" -" }\n" -" }\n" -"\n" -" pub fn name(mut self, bar: String) -> FooBuilder {\n" -" // Set the name on the builder itself, and return the builder by " -"value.\n" -" self.bar = bar;\n" -" self\n" -" }\n" -"\n" -" // If we can get away with not consuming the Builder here, that is an\n" +"// Set the name on the builder itself, and return the builder by value.\n" +msgstr "" + +#: src/patterns/creational/builder.md:43 +msgid "" +"// If we can get away with not consuming the Builder here, that is an\n" " // advantage. It means we can use the FooBuilder as a template for " "constructing\n" " // many Foos.\n" -" pub fn build(self) -> Foo {\n" -" // Create a Foo from the FooBuilder, applying all settings in " -"FooBuilder\n" +msgstr "" + +#: src/patterns/creational/builder.md:47 +msgid "" +"// Create a Foo from the FooBuilder, applying all settings in FooBuilder\n" " // to Foo.\n" -" Foo { bar: self.bar }\n" -" }\n" -"}\n" -"\n" -"#[test]\n" -"fn builder_test() {\n" -" let foo = Foo {\n" -" bar: String::from(\"Y\"),\n" -" };\n" -" let foo_from_builder: Foo = " -"FooBuilder::new().name(String::from(\"Y\")).build();\n" -" assert_eq!(foo, foo_from_builder);\n" -"}\n" -"```" msgstr "" -#: src\patterns/creational/builder.md:65 +#: src/patterns/creational/builder.md:56 src/patterns/creational/builder.md:58 +msgid "\"Y\"" +msgstr "" + +#: src/patterns/creational/builder.md:65 msgid "" -"Useful when you would otherwise require many constructors or where\n" +"Useful when you would otherwise require many constructors or where " "construction has side effects." msgstr "" -#: src\patterns/creational/builder.md:70 +#: src/patterns/creational/builder.md:70 msgid "Separates methods for building from other methods." msgstr "" -#: src\patterns/creational/builder.md:72 +#: src/patterns/creational/builder.md:72 msgid "Prevents proliferation of constructors." msgstr "" -#: src\patterns/creational/builder.md:74 +#: src/patterns/creational/builder.md:74 msgid "" "Can be used for one-liner initialisation as well as more complex " "construction." msgstr "" -#: src\patterns/creational/builder.md:78 +#: src/patterns/creational/builder.md:78 msgid "" -"More complex than creating a struct object directly, or a simple " -"constructor\n" +"More complex than creating a struct object directly, or a simple constructor " "function." msgstr "" -#: src\patterns/creational/builder.md:83 +#: src/patterns/creational/builder.md:83 msgid "" "This pattern is seen more frequently in Rust (and for simpler objects) than " -"in\n" -"many other languages because Rust lacks overloading. Since you can only have " -"a\n" -"single method with a given name, having multiple constructors is less nice " -"in\n" -"Rust than in C++, Java, or others." +"in many other languages because Rust lacks overloading. Since you can only " +"have a single method with a given name, having multiple constructors is less " +"nice in Rust than in C++, Java, or others." msgstr "" -#: src\patterns/creational/builder.md:88 +#: src/patterns/creational/builder.md:88 msgid "" "This pattern is often used where the builder object is useful in its own " -"right,\n" -"rather than being just a builder. For example, see\n" +"right, rather than being just a builder. For example, see " "[`std::process::Command`](https://doc.rust-lang.org/std/process/" -"struct.Command.html)\n" -"is a builder for [`Child`](https://doc.rust-lang.org/std/process/" -"struct.Child.html)\n" -"(a process). In these cases, the `T` and `TBuilder` naming pattern is not " -"used." +"struct.Command.html) is a builder for [`Child`](https://doc.rust-lang.org/" +"std/process/struct.Child.html) (a process). In these cases, the `T` and " +"`TBuilder` naming pattern is not used." msgstr "" -#: src\patterns/creational/builder.md:94 +#: src/patterns/creational/builder.md:95 msgid "" "The example takes and returns the builder by value. It is often more " -"ergonomic\n" -"(and more efficient) to take and return the builder as a mutable reference. " -"The\n" -"borrow checker makes this work naturally. This approach has the advantage " -"that\n" -"one can write code like" +"ergonomic (and more efficient) to take and return the builder as a mutable " +"reference. The borrow checker makes this work naturally. This approach has " +"the advantage that one can write code like" msgstr "" -#: src\patterns/creational/builder.md:99 +#: src/patterns/creational/builder.md:107 +msgid "as well as the `FooBuilder::new().a().b().build()` style." +msgstr "" + +#: src/patterns/creational/builder.md:111 msgid "" -"```rust,ignore\n" -"let mut fb = FooBuilder::new();\n" -"fb.a();\n" -"fb.b();\n" -"let f = fb.build();\n" -"```" +"[Description in the style guide](https://web.archive.org/web/20210104103100/" +"https://doc.rust-lang.org/1.12.0/style/ownership/builders.html)" msgstr "" -#: src\patterns/creational/builder.md:106 -msgid "as well as the `FooBuilder::new().a().b().build()` style." +#: src/patterns/creational/builder.md:112 +msgid "" +"[derive_builder](https://crates.io/crates/derive_builder), a crate for " +"automatically implementing this pattern while avoiding the boilerplate." +msgstr "" + +#: src/patterns/creational/builder.md:114 +msgid "" +"[Constructor pattern](../../idioms/ctor.md) for when construction is simpler." msgstr "" -#: src\patterns/creational/builder.md:110 +#: src/patterns/creational/builder.md:115 msgid "" -"- [Description in the style guide](https://web.archive.org/web/" -"20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/" -"builders.html)\n" -"- [derive_builder](https://crates.io/crates/derive_builder), a crate for " -"automatically\n" -" implementing this pattern while avoiding the boilerplate.\n" -"- [Constructor pattern](../../idioms/ctor.md) for when construction is " -"simpler.\n" -"- [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/" -"Builder_pattern)\n" -"- [Construction of complex values](https://web.archive.org/web/" -"20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-" -"builder)" +"[Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern)" msgstr "" -#: src\patterns/creational/fold.md:1 -msgid "# Fold" +#: src/patterns/creational/builder.md:116 +msgid "" +"[Construction of complex values](https://web.archive.org/web/20210104103000/" +"https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder)" msgstr "" -#: src\patterns/creational/fold.md:5 +#: src/patterns/creational/fold.md:5 msgid "" "Run an algorithm over each item in a collection of data to create a new " -"item,\n" -"thus creating a whole new collection." +"item, thus creating a whole new collection." msgstr "" -#: src\patterns/creational/fold.md:8 +#: src/patterns/creational/fold.md:8 msgid "" -"The etymology here is unclear to me. The terms 'fold' and 'folder' are used\n" -"in the Rust compiler, although it appears to me to be more like a map than " -"a\n" +"The etymology here is unclear to me. The terms 'fold' and 'folder' are used " +"in the Rust compiler, although it appears to me to be more like a map than a " "fold in the usual sense. See the discussion below for more details." msgstr "" -#: src\patterns/creational/fold.md:14 +#: src/patterns/creational/fold.md:15 +msgid "// The data we will fold, a simple AST.\n" +msgstr "" + +#: src/patterns/creational/fold.md:32 +msgid "// The abstract folder\n" +msgstr "" + +#: src/patterns/creational/fold.md:38 msgid "" -"```rust,ignore\n" -"// The data we will fold, a simple AST.\n" -"mod ast {\n" -" pub enum Stmt {\n" -" Expr(Box),\n" -" Let(Box, Box),\n" -" }\n" -"\n" -" pub struct Name {\n" -" value: String,\n" -" }\n" -"\n" -" pub enum Expr {\n" -" IntLit(i64),\n" -" Add(Box, Box),\n" -" Sub(Box, Box),\n" -" }\n" -"}\n" -"\n" -"// The abstract folder\n" -"mod fold {\n" -" use ast::*;\n" -"\n" -" pub trait Folder {\n" -" // A leaf node just returns the node itself. In some cases, we can " -"do this\n" +"// A leaf node just returns the node itself. In some cases, we can do this\n" " // to inner nodes too.\n" -" fn fold_name(&mut self, n: Box) -> Box { n }\n" -" // Create a new inner node by folding its children.\n" -" fn fold_stmt(&mut self, s: Box) -> Box {\n" -" match *s {\n" -" Stmt::Expr(e) => Box::new(Stmt::Expr(self.fold_expr(e))),\n" -" Stmt::Let(n, e) => Box::new(Stmt::Let(self.fold_name(n), " -"self.fold_expr(e))),\n" -" }\n" -" }\n" -" fn fold_expr(&mut self, e: Box) -> Box { ... }\n" -" }\n" -"}\n" -"\n" -"use fold::*;\n" -"use ast::*;\n" -"\n" -"// An example concrete implementation - renames every name to 'foo'.\n" -"struct Renamer;\n" -"impl Folder for Renamer {\n" -" fn fold_name(&mut self, n: Box) -> Box {\n" -" Box::new(Name { value: \"foo\".to_owned() })\n" -" }\n" -" // Use the default methods for the other nodes.\n" -"}\n" -"```" msgstr "" -#: src\patterns/creational/fold.md:65 -msgid "" -"The result of running the `Renamer` on an AST is a new AST identical to the " -"old\n" -"one, but with every name changed to `foo`. A real life folder might have " -"some\n" -"state preserved between nodes in the struct itself." +#: src/patterns/creational/fold.md:41 +msgid "// Create a new inner node by folding its children.\n" +msgstr "" + +#: src/patterns/creational/fold.md:54 +msgid "// An example concrete implementation - renames every name to 'foo'.\n" +msgstr "" + +#: src/patterns/creational/fold.md:59 +msgid "\"foo\"" +msgstr "" + +#: src/patterns/creational/fold.md:61 +msgid "// Use the default methods for the other nodes.\n" +msgstr "" + +#: src/patterns/creational/fold.md:65 +msgid "" +"The result of running the `Renamer` on an AST is a new AST identical to the " +"old one, but with every name changed to `foo`. A real life folder might have " +"some state preserved between nodes in the struct itself." +msgstr "" + +#: src/patterns/creational/fold.md:69 +msgid "" +"A folder can also be defined to map one data structure to a different (but " +"usually similar) data structure. For example, we could fold an AST into a " +"HIR tree (HIR stands for high-level intermediate representation)." +msgstr "" + +#: src/patterns/creational/fold.md:75 +msgid "" +"It is common to want to map a data structure by performing some operation on " +"each node in the structure. For simple operations on simple data structures, " +"this can be done using `Iterator::map`. For more complex operations, perhaps " +"where earlier nodes can affect the operation on later nodes, or where " +"iteration over the data structure is non-trivial, using the fold pattern is " +"more appropriate." +msgstr "" + +#: src/patterns/creational/fold.md:82 +msgid "" +"Like the visitor pattern, the fold pattern allows us to separate traversal " +"of a data structure from the operations performed to each node." +msgstr "" + +#: src/patterns/creational/fold.md:87 +msgid "" +"Mapping data structures in this fashion is common in functional languages. " +"In OO languages, it would be more common to mutate the data structure in " +"place. The 'functional' approach is common in Rust, mostly due to the " +"preference for immutability. Using fresh data structures, rather than " +"mutating old ones, makes reasoning about the code easier in most " +"circumstances." +msgstr "" + +#: src/patterns/creational/fold.md:93 +msgid "" +"The trade-off between efficiency and reusability can be tweaked by changing " +"how nodes are accepted by the `fold_*` methods." +msgstr "" + +#: src/patterns/creational/fold.md:96 +msgid "" +"In the above example we operate on `Box` pointers. Since these own their " +"data exclusively, the original copy of the data structure cannot be re-used. " +"On the other hand if a node is not changed, reusing it is very efficient." +msgstr "" + +#: src/patterns/creational/fold.md:100 +msgid "" +"If we were to operate on borrowed references, the original data structure " +"can be reused; however, a node must be cloned even if unchanged, which can " +"be expensive." +msgstr "" + +#: src/patterns/creational/fold.md:104 +msgid "" +"Using a reference counted pointer gives the best of both worlds - we can " +"reuse the original data structure, and we don't need to clone unchanged " +"nodes. However, they are less ergonomic to use and mean that the data " +"structures cannot be mutable." +msgstr "" + +#: src/patterns/creational/fold.md:111 +msgid "" +"Iterators have a `fold` method, however this folds a data structure into a " +"value, rather than into a new data structure. An iterator's `map` is more " +"like this fold pattern." +msgstr "" + +#: src/patterns/creational/fold.md:115 +msgid "" +"In other languages, fold is usually used in the sense of Rust's iterators, " +"rather than this pattern. Some functional languages have powerful constructs " +"for performing flexible maps over data structures." +msgstr "" + +#: src/patterns/creational/fold.md:119 +msgid "" +"The [visitor](../behavioural/visitor.md) pattern is closely related to fold. " +"They share the concept of walking a data structure performing an operation " +"on each node. However, the visitor does not create a new data structure nor " +"consume the old one." +msgstr "" + +#: src/patterns/structural/intro.md:1 +msgid "Structural Patterns" +msgstr "" + +#: src/patterns/structural/intro.md:3 +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +msgstr "" + +#: src/patterns/structural/intro.md:5 +msgid "" +"Design patterns that ease the design by identifying a simple way to realize " +"relationships among entities." +msgstr "" + +#: src/patterns/structural/compose-structs.md:1 +msgid "Struct decomposition for independent borrowing" +msgstr "" + +#: src/patterns/structural/compose-structs.md:5 +msgid "" +"Sometimes a large struct will cause issues with the borrow checker - " +"although fields can be borrowed independently, sometimes the whole struct " +"ends up being used at once, preventing other uses. A solution might be to " +"decompose the struct into several smaller structs. Then compose these " +"together into the original struct. Then each struct can be borrowed " +"separately and have more flexible behaviour." +msgstr "" + +#: src/patterns/structural/compose-structs.md:12 +msgid "" +"This will often lead to a better design in other ways: applying this design " +"pattern often reveals smaller units of functionality." +msgstr "" + +#: src/patterns/structural/compose-structs.md:17 +msgid "" +"Here is a contrived example of where the borrow checker foils us in our plan " +"to use a struct:" +msgstr "" + +#: src/patterns/structural/compose-structs.md:28 +msgid "\"Connection string: {}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:29 +msgid "\"Timeout: {}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:30 +msgid "\"Pool size: {}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:35 +msgid "\"initial string\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:42 +#: src/patterns/structural/compose-structs.md:96 +msgid "\"new string\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:46 +msgid "The compiler throws following errors:" +msgstr "" + +#: src/patterns/structural/compose-structs.md:48 +msgid "" +"```ignore\n" +"let connection_string = &mut db.connection_string;\n" +" ------------------------- mutable borrow occurs " +"here\n" +"print_database(&db);\n" +" ^^^ immutable borrow occurs here\n" +"*connection_string = \"new string\".to_string();\n" +"------------------ mutable borrow later used here\n" +"```" +msgstr "" + +#: src/patterns/structural/compose-structs.md:57 +msgid "" +"We can apply this design pattern and refactor `Database` into three smaller " +"structs, thus solving the borrow checking issue:" +msgstr "" + +#: src/patterns/structural/compose-structs.md:61 +msgid "" +"// Database is now composed of three structs - ConnectionString, Timeout and " +"PoolSize.\n" +"// Let's decompose it into smaller structs\n" +msgstr "" + +#: src/patterns/structural/compose-structs.md:71 +msgid "// We then compose these smaller structs back into `Database`\n" +msgstr "" + +#: src/patterns/structural/compose-structs.md:78 +msgid "" +"// print_database can then take ConnectionString, Timeout and Poolsize " +"struct instead\n" +msgstr "" + +#: src/patterns/structural/compose-structs.md:81 +msgid "\"Connection string: {connection_str:?}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:82 +msgid "\"Timeout: {timeout:?}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:83 +msgid "\"Pool size: {pool_size:?}\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:87 +msgid "// Initialize the Database with the three structs\n" +msgstr "" + +#: src/patterns/structural/compose-structs.md:89 +msgid "\"localhost\"" +msgstr "" + +#: src/patterns/structural/compose-structs.md:102 +msgid "" +"This pattern is most useful, when you have a struct that ended up with a lot " +"of fields that you want to borrow independently. Thus having a more flexible " +"behaviour in the end." +msgstr "" + +#: src/patterns/structural/compose-structs.md:108 +msgid "" +"Decomposition of structs lets you work around limitations in the borrow " +"checker. And it often produces a better design." +msgstr "" + +#: src/patterns/structural/compose-structs.md:113 +msgid "" +"It can lead to more verbose code. And sometimes, the smaller structs are not " +"good abstractions, and so we end up with a worse design. That is probably a " +"'code smell', indicating that the program should be refactored in some way." +msgstr "" + +#: src/patterns/structural/compose-structs.md:119 +msgid "" +"This pattern is not required in languages that don't have a borrow checker, " +"so in that sense is unique to Rust. However, making smaller units of " +"functionality often leads to cleaner code: a widely acknowledged principle " +"of software engineering, independent of the language." +msgstr "" + +#: src/patterns/structural/compose-structs.md:124 +msgid "" +"This pattern relies on Rust's borrow checker to be able to borrow fields " +"independently of each other. In the example, the borrow checker knows that " +"`a.b` and `a.c` are distinct and can be borrowed independently, it does not " +"try to borrow all of `a`, which would make this pattern useless." +msgstr "" + +#: src/patterns/structural/small-crates.md:1 +msgid "Prefer small crates" +msgstr "" + +#: src/patterns/structural/small-crates.md:5 +msgid "Prefer small crates that do one thing well." +msgstr "" + +#: src/patterns/structural/small-crates.md:7 +msgid "" +"Cargo and crates.io make it easy to add third-party libraries, much more so " +"than in say C or C++. Moreover, since packages on crates.io cannot be edited " +"or removed after publication, any build that works now should continue to " +"work in the future. We should take advantage of this tooling, and use " +"smaller, more fine-grained dependencies." +msgstr "" + +#: src/patterns/structural/small-crates.md:15 +msgid "Small crates are easier to understand, and encourage more modular code." +msgstr "" + +#: src/patterns/structural/small-crates.md:16 +msgid "" +"Crates allow for re-using code between projects. For example, the `url` " +"crate was developed as part of the Servo browser engine, but has since found " +"wide use outside the project." +msgstr "" + +#: src/patterns/structural/small-crates.md:19 +msgid "" +"Since the compilation unit of Rust is the crate, splitting a project into " +"multiple crates can allow more of the code to be built in parallel." +msgstr "" + +#: src/patterns/structural/small-crates.md:24 +msgid "" +"This can lead to \"dependency hell\", when a project depends on multiple " +"conflicting versions of a crate at the same time. For example, the `url` " +"crate has both versions 1.0 and 0.5. Since the `Url` from `url:1.0` and the " +"`Url` from `url:0.5` are different types, an HTTP client that uses `url:0.5` " +"would not accept `Url` values from a web scraper that uses `url:1.0`." +msgstr "" + +#: src/patterns/structural/small-crates.md:29 +msgid "" +"Packages on crates.io are not curated. A crate may be poorly written, have " +"unhelpful documentation, or be outright malicious." +msgstr "" + +#: src/patterns/structural/small-crates.md:31 +msgid "" +"Two small crates may be less optimized than one large one, since the " +"compiler does not perform link-time optimization (LTO) by default." +msgstr "" + +#: src/patterns/structural/small-crates.md:36 +msgid "" +"The [`url`](https://crates.io/crates/url) crate provides tools for working " +"with URLs." +msgstr "" + +#: src/patterns/structural/small-crates.md:39 +msgid "" +"The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a " +"function to query the number of CPUs on a machine." +msgstr "" + +#: src/patterns/structural/small-crates.md:42 +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions for converting `&T` to `&[T]`. (Historical example)" +msgstr "" + +#: src/patterns/structural/small-crates.md:47 +msgid "[crates.io: The Rust community crate host](https://crates.io/)" +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:5 +msgid "" +"If you have `unsafe` code, create the smallest possible module that can " +"uphold the needed invariants to build a minimal safe interface upon the " +"unsafety. Embed this into a larger module that contains only safe code and " +"presents an ergonomic interface. Note that the outer module can contain " +"unsafe functions and methods that call directly into the unsafe code. Users " +"may use this to gain speed benefits." +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:14 +msgid "This restricts the unsafe code that must be audited" +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:15 +msgid "" +"Writing the outer module is much easier, since you can count on the " +"guarantees of the inner module" +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:20 +msgid "Sometimes, it may be hard to find a suitable interface." +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:21 +msgid "The abstraction may introduce inefficiencies." +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:25 +msgid "" +"The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe " +"operations in submodules, presenting a safe interface to users." +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:27 +msgid "" +"`std`'s `String` class is a wrapper over `Vec` with the added invariant " +"that the contents must be valid UTF-8. The operations on `String` ensure " +"this behavior. However, users have the option of using an `unsafe` method to " +"create a `String`, in which case the onus is on them to guarantee the " +"validity of the contents." +msgstr "" + +#: src/patterns/structural/unsafe-mods.md:35 +msgid "" +"[Ralf Jung's Blog about invariants in unsafe code](https://www.ralfj.de/blog/" +"2018/08/22/two-kinds-of-invariants.html)" +msgstr "" + +#: src/patterns/ffi/intro.md:1 +msgid "FFI Patterns" +msgstr "" + +#: src/patterns/ffi/intro.md:3 +msgid "" +"Writing FFI code is an entire course in itself. However, there are several " +"idioms here that can act as pointers, and avoid traps for inexperienced " +"users of unsafe Rust." +msgstr "" + +#: src/patterns/ffi/intro.md:7 +msgid "" +"This section contains design patterns that may be useful when doing FFI." +msgstr "" + +#: src/patterns/ffi/intro.md:9 +msgid "" +"[Object-Based API](./export.md) design that has good memory safety " +"characteristics, and a clean boundary of what is safe and what is unsafe" +msgstr "" + +#: src/patterns/ffi/intro.md:12 +msgid "" +"[Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust " +"types together into an opaque \"object\"" +msgstr "" + +#: src/patterns/ffi/export.md:5 +msgid "" +"When designing APIs in Rust which are exposed to other languages, there are " +"some important design principles which are contrary to normal Rust API " +"design:" +msgstr "" + +#: src/patterns/ffi/export.md:8 +msgid "" +"All Encapsulated types should be _owned_ by Rust, _managed_ by the user, and " +"_opaque_." +msgstr "" + +#: src/patterns/ffi/export.md:10 +msgid "" +"All Transactional data types should be _owned_ by the user, and " +"_transparent_." +msgstr "" + +#: src/patterns/ffi/export.md:12 +msgid "" +"All library behavior should be functions acting upon Encapsulated types." +msgstr "" + +#: src/patterns/ffi/export.md:13 +msgid "" +"All library behavior should be encapsulated into types not based on " +"structure, but _provenance/lifetime_." +msgstr "" + +#: src/patterns/ffi/export.md:18 +msgid "" +"Rust has built-in FFI support to other languages. It does this by providing " +"a way for crate authors to provide C-compatible APIs through different ABIs " +"(though that is unimportant to this practice)." +msgstr "" + +#: src/patterns/ffi/export.md:22 +msgid "" +"Well-designed Rust FFI follows C API design principles, while compromising " +"the design in Rust as little as possible. There are three goals with any " +"foreign API:" +msgstr "" + +#: src/patterns/ffi/export.md:26 +msgid "Make it easy to use in the target language." +msgstr "" + +#: src/patterns/ffi/export.md:27 +msgid "" +"Avoid the API dictating internal unsafety on the Rust side as much as " +"possible." +msgstr "" + +#: src/patterns/ffi/export.md:29 +msgid "" +"Keep the potential for memory unsafety and Rust `undefined behaviour` as " +"small as possible." +msgstr "" + +#: src/patterns/ffi/export.md:32 +msgid "" +"Rust code must trust the memory safety of the foreign language beyond a " +"certain point. However, every bit of `unsafe` code on the Rust side is an " +"opportunity for bugs, or to exacerbate `undefined behaviour`." +msgstr "" + +#: src/patterns/ffi/export.md:36 +msgid "" +"For example, if a pointer provenance is wrong, that may be a segfault due to " +"invalid memory access. But if it is manipulated by unsafe code, it could " +"become full-blown heap corruption." +msgstr "" + +#: src/patterns/ffi/export.md:40 +msgid "" +"The Object-Based API design allows for writing shims that have good memory " +"safety characteristics, and a clean boundary of what is safe and what is " +"`unsafe`." +msgstr "" + +#: src/patterns/ffi/export.md:46 +msgid "" +"The POSIX standard defines the API to access an on-file database, known as " +"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/" +"ndbm.h). It is an excellent example of an \"object-based\" API." +msgstr "" + +#: src/patterns/ffi/export.md:50 +msgid "" +"Here is the definition in C, which hopefully should be easy to read for " +"those involved in FFI. The commentary below should help explain it for those " +"who miss the subtleties." +msgstr "" + +#: src/patterns/ffi/export.md:69 +msgid "This API defines two types: `DBM` and `datum`." +msgstr "" + +#: src/patterns/ffi/export.md:71 +msgid "" +"The `DBM` type was called an \"encapsulated\" type above. It is designed to " +"contain internal state, and acts as an entry point for the library's " +"behavior." +msgstr "" + +#: src/patterns/ffi/export.md:74 +msgid "" +"It is completely opaque to the user, who cannot create a `DBM` themselves " +"since they don't know its size or layout. Instead, they must call " +"`dbm_open`, and that only gives them _a pointer to one_." +msgstr "" + +#: src/patterns/ffi/export.md:78 +msgid "" +"This means all `DBM`s are \"owned\" by the library in a Rust sense. The " +"internal state of unknown size is kept in memory controlled by the library, " +"not the user. The user can only manage its life cycle with `open` and " +"`close`, and perform operations on it with the other functions." +msgstr "" + +#: src/patterns/ffi/export.md:83 +msgid "" +"The `datum` type was called a \"transactional\" type above. It is designed " +"to facilitate the exchange of information between the library and its user." +msgstr "" + +#: src/patterns/ffi/export.md:86 +msgid "" +"The database is designed to store \"unstructured data\", with no pre-defined " +"length or meaning. As a result, the `datum` is the C equivalent of a Rust " +"slice: a bunch of bytes, and a count of how many there are. The main " +"difference is that there is no type information, which is what `void` " +"indicates." +msgstr "" + +#: src/patterns/ffi/export.md:91 +msgid "" +"Keep in mind that this header is written from the library's point of view. " +"The user likely has some type they are using, which has a known size. But " +"the library does not care, and by the rules of C casting, any type behind a " +"pointer can be cast to `void`." +msgstr "" + +#: src/patterns/ffi/export.md:96 +msgid "" +"As noted earlier, this type is _transparent_ to the user. But also, this " +"type is _owned_ by the user. This has subtle ramifications, due to that " +"pointer inside it. The question is, who owns the memory that pointer points " +"to?" +msgstr "" + +#: src/patterns/ffi/export.md:100 +msgid "" +"The answer for best memory safety is, \"the user\". But in cases such as " +"retrieving a value, the user does not know how to allocate it correctly " +"(since they don't know how long the value is). In this case, the library " +"code is expected to use the heap that the user has access to -- such as the " +"C library `malloc` and `free` -- and then _transfer ownership_ in the Rust " +"sense." +msgstr "" + +#: src/patterns/ffi/export.md:106 +msgid "" +"This may all seem speculative, but this is what a pointer means in C. It " +"means the same thing as Rust: \"user defined lifetime.\" The user of the " +"library needs to read the documentation in order to use it correctly. That " +"said, there are some decisions that have fewer or greater consequences if " +"users do it wrong. Minimizing those are what this best practice is about, " +"and the key is to _transfer ownership of everything that is transparent_." +msgstr "" + +#: src/patterns/ffi/export.md:115 +msgid "" +"This minimizes the number of memory safety guarantees the user must uphold " +"to a relatively small number:" +msgstr "" + +#: src/patterns/ffi/export.md:118 +msgid "" +"Do not call any function with a pointer not returned by `dbm_open` (invalid " +"access or corruption)." +msgstr "" + +#: src/patterns/ffi/export.md:120 +msgid "Do not call any function on a pointer after close (use after free)." +msgstr "" + +#: src/patterns/ffi/export.md:121 +msgid "" +"The `dptr` on any `datum` must be `NULL`, or point to a valid slice of " +"memory at the advertised length." +msgstr "" + +#: src/patterns/ffi/export.md:124 +msgid "" +"In addition, it avoids a lot of pointer provenance issues. To understand " +"why, let us consider an alternative in some depth: key iteration." +msgstr "" + +#: src/patterns/ffi/export.md:127 +msgid "" +"Rust is well known for its iterators. When implementing one, the programmer " +"makes a separate type with a bounded lifetime to its owner, and implements " +"the `Iterator` trait." +msgstr "" + +#: src/patterns/ffi/export.md:131 +msgid "Here is how iteration would be done in Rust for `DBM`:" +msgstr "" + +#: src/patterns/ffi/export.md:149 +msgid "" +"This is clean, idiomatic, and safe. thanks to Rust's guarantees. However, " +"consider what a straightforward API translation would look like:" +msgstr "" + +#: src/patterns/ffi/export.md:155 src/patterns/ffi/export.md:162 +#: src/patterns/ffi/export.md:166 +msgid "" +"// THIS API IS A BAD IDEA! For real applications, use object-based design " +"instead.\n" +msgstr "" + +#: src/patterns/ffi/export.md:170 +msgid "" +"This API loses a key piece of information: the lifetime of the iterator must " +"not exceed the lifetime of the `Dbm` object that owns it. A user of the " +"library could use it in a way which causes the iterator to outlive the data " +"it is iterating on, resulting in reading uninitialized memory." +msgstr "" + +#: src/patterns/ffi/export.md:175 +msgid "" +"This example written in C contains a bug that will be explained afterwards:" +msgstr "" + +#: src/patterns/ffi/export.md:179 +msgid "// DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG!\n" +msgstr "" + +#: src/patterns/ffi/export.md:189 +msgid "// an error is indicated by -1\n" +msgstr "" + +#: src/patterns/ffi/export.md:192 +msgid "// end of the iterator\n" +msgstr "" + +#: src/patterns/ffi/export.md:204 +msgid "" +"This bug is a classic. Here's what happens when the iterator returns the end-" +"of-iteration marker:" +msgstr "" + +#: src/patterns/ffi/export.md:207 +msgid "" +"The loop condition sets `l` to zero, and enters the loop because `0 >= 0`." +msgstr "" + +#: src/patterns/ffi/export.md:208 +msgid "The length is incremented, in this case by zero." +msgstr "" + +#: src/patterns/ffi/export.md:209 +msgid "" +"The if statement is true, so the database is closed. There should be a break " +"statement here." +msgstr "" + +#: src/patterns/ffi/export.md:211 +msgid "" +"The loop condition executes again, causing a `next` call on the closed " +"object." +msgstr "" + +#: src/patterns/ffi/export.md:214 +msgid "" +"The worst part about this bug? If the Rust implementation was careful, this " +"code will work most of the time! If the memory for the `Dbm` object is not " +"immediately reused, an internal check will almost certainly fail, resulting " +"in the iterator returning a `-1` indicating an error. But occasionally, it " +"will cause a segmentation fault, or even worse, nonsensical memory " +"corruption!" +msgstr "" + +#: src/patterns/ffi/export.md:220 +msgid "" +"None of this can be avoided by Rust. From its perspective, it put those " +"objects on its heap, returned pointers to them, and gave up control of their " +"lifetimes. The C code simply must \"play nice\"." +msgstr "" + +#: src/patterns/ffi/export.md:224 +msgid "" +"The programmer must read and understand the API documentation. While some " +"consider that par for the course in C, a good API design can mitigate this " +"risk. The POSIX API for `DBM` did this by _consolidating the ownership_ of " +"the iterator with its parent:" +msgstr "" + +#: src/patterns/ffi/export.md:234 +msgid "" +"Thus, all the lifetimes were bound together, and such unsafety was prevented." +msgstr "" + +#: src/patterns/ffi/export.md:238 +msgid "" +"However, this design choice also has a number of drawbacks, which should be " +"considered as well." +msgstr "" + +#: src/patterns/ffi/export.md:241 +msgid "" +"First, the API itself becomes less expressive. With POSIX DBM, there is only " +"one iterator per object, and every call changes its state. This is much more " +"restrictive than iterators in almost any language, even though it is safe. " +"Perhaps with other related objects, whose lifetimes are less hierarchical, " +"this limitation is more of a cost than the safety." +msgstr "" + +#: src/patterns/ffi/export.md:247 +msgid "" +"Second, depending on the relationships of the API's parts, significant " +"design effort may be involved. Many of the easier design points have other " +"patterns associated with them:" +msgstr "" + +#: src/patterns/ffi/export.md:251 +msgid "" +"[Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types " +"together into an opaque \"object\"" +msgstr "" + +#: src/patterns/ffi/export.md:254 +msgid "" +"[FFI Error Passing](../../idioms/ffi/errors.md) explains error handling with " +"integer codes and sentinel return values (such as `NULL` pointers)" +msgstr "" + +#: src/patterns/ffi/export.md:257 +msgid "" +"[Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) allows " +"accepting strings with minimal unsafe code, and is easier to get right than " +"[Passing Strings to FFI](../../idioms/ffi/passing-strings.md)" +msgstr "" + +#: src/patterns/ffi/export.md:261 +msgid "" +"However, not every API can be done this way. It is up to the best judgement " +"of the programmer as to who their audience is." +msgstr "" + +#: src/patterns/ffi/wrappers.md:5 +msgid "" +"This pattern is designed to allow gracefully handling multiple related " +"types, while minimizing the surface area for memory unsafety." +msgstr "" + +#: src/patterns/ffi/wrappers.md:8 +msgid "" +"One of the cornerstones of Rust's aliasing rules is lifetimes. This ensures " +"that many patterns of access between types can be memory safe, data race " +"safety included." +msgstr "" + +#: src/patterns/ffi/wrappers.md:12 +msgid "" +"However, when Rust types are exported to other languages, they are usually " +"transformed into pointers. In Rust, a pointer means \"the user manages the " +"lifetime of the pointee.\" It is their responsibility to avoid memory " +"unsafety." +msgstr "" + +#: src/patterns/ffi/wrappers.md:16 +msgid "" +"Some level of trust in the user code is thus required, notably around use-" +"after-free which Rust can do nothing about. However, some API designs place " +"higher burdens than others on the code written in the other language." +msgstr "" + +#: src/patterns/ffi/wrappers.md:20 +msgid "" +"The lowest risk API is the \"consolidated wrapper\", where all possible " +"interactions with an object are folded into a \"wrapper type\", while " +"keeping the Rust API clean." +msgstr "" + +#: src/patterns/ffi/wrappers.md:26 +msgid "" +"To understand this, let us look at a classic example of an API to export: " +"iteration through a collection." +msgstr "" + +#: src/patterns/ffi/wrappers.md:29 +msgid "That API looks like this:" +msgstr "" + +#: src/patterns/ffi/wrappers.md:31 +msgid "The iterator is initialized with `first_key`." +msgstr "" + +#: src/patterns/ffi/wrappers.md:32 +msgid "Each call to `next_key` will advance the iterator." msgstr "" -#: src\patterns/creational/fold.md:69 -msgid "" -"A folder can also be defined to map one data structure to a different (but\n" -"usually similar) data structure. For example, we could fold an AST into a " -"HIR\n" -"tree (HIR stands for high-level intermediate representation)." +#: src/patterns/ffi/wrappers.md:33 +msgid "Calls to `next_key` if the iterator is at the end will do nothing." msgstr "" -#: src\patterns/creational/fold.md:75 +#: src/patterns/ffi/wrappers.md:34 msgid "" -"It is common to want to map a data structure by performing some operation " -"on\n" -"each node in the structure. For simple operations on simple data " -"structures,\n" -"this can be done using `Iterator::map`. For more complex operations, " -"perhaps\n" -"where earlier nodes can affect the operation on later nodes, or where " -"iteration\n" -"over the data structure is non-trivial, using the fold pattern is more\n" -"appropriate." +"As noted above, the iterator is \"wrapped into\" the collection (unlike the " +"native Rust API)." msgstr "" -#: src\patterns/creational/fold.md:82 +#: src/patterns/ffi/wrappers.md:37 msgid "" -"Like the visitor pattern, the fold pattern allows us to separate traversal " -"of a\n" -"data structure from the operations performed to each node." +"If the iterator implements `nth()` efficiently, then it is possible to make " +"it ephemeral to each function call:" msgstr "" -#: src\patterns/creational/fold.md:87 -msgid "" -"Mapping data structures in this fashion is common in functional languages. " -"In OO\n" -"languages, it would be more common to mutate the data structure in place. " -"The\n" -"'functional' approach is common in Rust, mostly due to the preference for\n" -"immutability. Using fresh data structures, rather than mutating old ones, " -"makes\n" -"reasoning about the code easier in most circumstances." +#: src/patterns/ffi/wrappers.md:62 +msgid "As a result, the wrapper is simple and contains no `unsafe` code." msgstr "" -#: src\patterns/creational/fold.md:93 +#: src/patterns/ffi/wrappers.md:66 msgid "" -"The trade-off between efficiency and reusability can be tweaked by changing " -"how\n" -"nodes are accepted by the `fold_*` methods." +"This makes APIs safer to use, avoiding issues with lifetimes between types. " +"See [Object-Based APIs](./export.md) for more on the advantages and pitfalls " +"this avoids." msgstr "" -#: src\patterns/creational/fold.md:96 +#: src/patterns/ffi/wrappers.md:72 msgid "" -"In the above example we operate on `Box` pointers. Since these own their " -"data\n" -"exclusively, the original copy of the data structure cannot be re-used. On " -"the\n" -"other hand if a node is not changed, reusing it is very efficient." +"Often, wrapping types is quite difficult, and sometimes a Rust API " +"compromise would make things easier." msgstr "" -#: src\patterns/creational/fold.md:100 +#: src/patterns/ffi/wrappers.md:75 msgid "" -"If we were to operate on borrowed references, the original data structure " -"can be\n" -"reused; however, a node must be cloned even if unchanged, which can be\n" -"expensive." +"As an example, consider an iterator which does not efficiently implement " +"`nth()`. It would definitely be worth putting in special logic to make the " +"object handle iteration internally, or to support a different access pattern " +"efficiently that only the Foreign Function API will use." msgstr "" -#: src\patterns/creational/fold.md:104 -msgid "" -"Using a reference counted pointer gives the best of both worlds - we can " -"reuse\n" -"the original data structure, and we don't need to clone unchanged nodes. " -"However,\n" -"they are less ergonomic to use and mean that the data structures cannot be\n" -"mutable." +#: src/patterns/ffi/wrappers.md:80 +msgid "Trying to Wrap Iterators (and Failing)" msgstr "" -#: src\patterns/creational/fold.md:111 +#: src/patterns/ffi/wrappers.md:82 msgid "" -"Iterators have a `fold` method, however this folds a data structure into a\n" -"value, rather than into a new data structure. An iterator's `map` is more " -"like\n" -"this fold pattern." +"To wrap any type of iterator into the API correctly, the wrapper would need " +"to do what a C version of the code would do: erase the lifetime of the " +"iterator, and manage it manually." msgstr "" -#: src\patterns/creational/fold.md:115 -msgid "" -"In other languages, fold is usually used in the sense of Rust's iterators,\n" -"rather than this pattern. Some functional languages have powerful constructs " -"for\n" -"performing flexible maps over data structures." +#: src/patterns/ffi/wrappers.md:86 +msgid "Suffice it to say, this is _incredibly_ difficult." msgstr "" -#: src\patterns/creational/fold.md:119 -msgid "" -"The [visitor](../behavioural/visitor.md) pattern is closely related to " -"fold.\n" -"They share the concept of walking a data structure performing an operation " -"on\n" -"each node. However, the visitor does not create a new data structure nor " -"consume\n" -"the old one." +#: src/patterns/ffi/wrappers.md:88 +msgid "Here is an illustration of just _one_ pitfall." msgstr "" -#: src\patterns/structural/intro.md:1 -msgid "# Structural Patterns" +#: src/patterns/ffi/wrappers.md:90 +msgid "A first version of `MySetWrapper` would look like this:" msgstr "" -#: src\patterns/structural/intro.md:3 -msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +#: src/patterns/ffi/wrappers.md:96 +msgid "// created from a transmuted Box\n" msgstr "" -#: src\patterns/structural/intro.md:5 +#: src/patterns/ffi/wrappers.md:101 msgid "" -"> Design patterns that ease the design by identifying a simple way to " -"realize relationships\n" -"> among entities." +"With `transmute` being used to extend a lifetime, and a pointer to hide it, " +"it's ugly already. But it gets even worse: _any other operation can cause " +"Rust `undefined behaviour`_." msgstr "" -#: src\patterns/structural/compose-structs.md:1 -msgid "# Compose structs together for better borrowing" +#: src/patterns/ffi/wrappers.md:105 +msgid "" +"Consider that the `MySet` in the wrapper could be manipulated by other " +"functions during iteration, such as storing a new value to the key it was " +"iterating over. The API doesn't discourage this, and in fact some similar C " +"libraries expect it." msgstr "" -#: src\patterns/structural/compose-structs.md:3 -msgid "TODO - this is not a very snappy name" +#: src/patterns/ffi/wrappers.md:109 +msgid "A simple implementation of `myset_store` would be:" msgstr "" -#: src\patterns/structural/compose-structs.md:7 -msgid "" -"Sometimes a large struct will cause issues with the borrow checker - " -"although\n" -"fields can be borrowed independently, sometimes the whole struct ends up " -"being\n" -"used at once, preventing other uses. A solution might be to decompose the " -"struct\n" -"into several smaller structs. Then compose these together into the original\n" -"struct. Then each struct can be borrowed separately and have more flexible\n" -"behaviour." +#: src/patterns/ffi/wrappers.md:117 +msgid "// DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROBLEM.\n" msgstr "" -#: src\patterns/structural/compose-structs.md:14 -msgid "" -"This will often lead to a better design in other ways: applying this design\n" -"pattern often reveals smaller units of functionality." +#: src/patterns/ffi/wrappers.md:120 +msgid "// SAFETY: whoops, UB occurs in here!\n" msgstr "" -#: src\patterns/structural/compose-structs.md:19 -msgid "" -"Here is a contrived example of where the borrow checker foils us in our plan " -"to\n" -"use a struct:" +#: src/patterns/ffi/wrappers.md:124 +msgid "/* ...check and cast key and value data... */" msgstr "" -#: src\patterns/structural/compose-structs.md:22 +#: src/patterns/ffi/wrappers.md:134 msgid "" -"```rust\n" -"struct A {\n" -" f1: u32,\n" -" f2: u32,\n" -" f3: u32,\n" -"}\n" -"\n" -"fn foo(a: &mut A) -> &u32 { &a.f2 }\n" -"fn bar(a: &mut A) -> u32 { a.f1 + a.f3 }\n" -"\n" -"fn baz(a: &mut A) {\n" -" // The later usage of x causes a to be borrowed for the rest of the " -"function.\n" -" let x = foo(a);\n" -" // Borrow checker error:\n" -" // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than " -"once\n" -" // at a time\n" -" println!(\"{}\", x);\n" -"}\n" -"```" +"If the iterator exists when this function is called, we have violated one of " +"Rust's aliasing rules. According to Rust, the mutable reference in this " +"block must have _exclusive_ access to the object. If the iterator simply " +"exists, it's not exclusive, so we have `undefined behaviour`! [^1]" msgstr "" -#: src\patterns/structural/compose-structs.md:42 +#: src/patterns/ffi/wrappers.md:139 msgid "" -"We can apply this design pattern and refactor `A` into two smaller structs, " -"thus\n" -"solving the borrow checking issue:" +"To avoid this, we must have a way of ensuring that mutable reference really " +"is exclusive. That basically means clearing out the iterator's shared " +"reference while it exists, and then reconstructing it. In most cases, that " +"will still be less efficient than the C version." msgstr "" -#: src\patterns/structural/compose-structs.md:45 +#: src/patterns/ffi/wrappers.md:144 msgid "" -"```rust\n" -"// A is now composed of two structs - B and C.\n" -"struct A {\n" -" b: B,\n" -" c: C,\n" -"}\n" -"struct B {\n" -" f2: u32,\n" -"}\n" -"struct C {\n" -" f1: u32,\n" -" f3: u32,\n" -"}\n" -"\n" -"// These functions take a B or C, rather than A.\n" -"fn foo(b: &mut B) -> &u32 { &b.f2 }\n" -"fn bar(c: &mut C) -> u32 { c.f1 + c.f3 }\n" -"\n" -"fn baz(a: &mut A) {\n" -" let x = foo(&mut a.b);\n" -" // Now it's OK!\n" -" let y = bar(&mut a.c);\n" -" println!(\"{}\", x);\n" -"}\n" -"```" +"Some may ask: how can C do this more efficiently? The answer is, it cheats. " +"Rust's aliasing rules are the problem, and C simply ignores them for its " +"pointers. In exchange, it is common to see code that is declared in the " +"manual as \"not thread safe\" under some or all circumstances. In fact, the " +"[GNU C library](https://manpages.debian.org/buster/manpages/" +"attributes.7.en.html) has an entire lexicon dedicated to concurrent behavior!" msgstr "" -#: src\patterns/structural/compose-structs.md:73 -msgid "TODO Why and where you should use the pattern" +#: src/patterns/ffi/wrappers.md:151 +msgid "" +"Rust would rather make everything memory safe all the time, for both safety " +"and optimizations that C code cannot attain. Being denied access to certain " +"shortcuts is the price Rust programmers need to pay." msgstr "" -#: src\patterns/structural/compose-structs.md:77 -msgid "Lets you work around limitations in the borrow checker." +#: src/patterns/ffi/wrappers.md:155 +msgid "" +"For the C programmers out there scratching their heads, the iterator need " +"not be read _during_ this code to cause the UB. The exclusivity rule also " +"enables compiler optimizations which may cause inconsistent observations by " +"the iterator's shared reference (e.g. stack spills or reordering " +"instructions for efficiency). These observations may happen _any time after_ " +"the mutable reference is created." msgstr "" -#: src\patterns/structural/compose-structs.md:79 -msgid "Often produces a better design." +#: src/anti_patterns/index.md:3 +msgid "" +"An [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern) is a solution " +"to a \"recurring problem that is usually ineffective and risks being highly " +"counterproductive\". Just as valuable as knowing how to solve a problem, is " +"knowing how _not_ to solve it. Anti-patterns give us great counter-examples " +"to consider relative to design patterns. Anti-patterns are not confined to " +"code. For example, a process can be an anti-pattern, too." msgstr "" -#: src\patterns/structural/compose-structs.md:83 -msgid "Leads to more verbose code." +#: src/anti_patterns/borrow_clone.md:5 +msgid "" +"The borrow checker prevents Rust users from developing otherwise unsafe code " +"by ensuring that either: only one mutable reference exists, or potentially " +"many but all immutable references exist. If the code written does not hold " +"true to these conditions, this anti-pattern arises when the developer " +"resolves the compiler error by cloning the variable." msgstr "" -#: src\patterns/structural/compose-structs.md:85 -msgid "" -"Sometimes, the smaller structs are not good abstractions, and so we end up " -"with\n" -"a worse design. That is probably a 'code smell', indicating that the " -"program\n" -"should be refactored in some way." +#: src/anti_patterns/borrow_clone.md:14 +msgid "// define any variable\n" msgstr "" -#: src\patterns/structural/compose-structs.md:91 -msgid "" -"This pattern is not required in languages that don't have a borrow checker, " -"so\n" -"in that sense is unique to Rust. However, making smaller units of " -"functionality\n" -"often leads to cleaner code: a widely acknowledged principle of software\n" -"engineering, independent of the language." +#: src/anti_patterns/borrow_clone.md:16 +msgid "// Borrow `x` -- but clone it first\n" msgstr "" -#: src\patterns/structural/compose-structs.md:96 +#: src/anti_patterns/borrow_clone.md:19 msgid "" -"This pattern relies on Rust's borrow checker to be able to borrow fields\n" -"independently of each other. In the example, the borrow checker knows that " -"`a.b`\n" -"and `a.c` are distinct and can be borrowed independently, it does not try " -"to\n" -"borrow all of `a`, which would make this pattern useless." +"// without the x.clone() two lines prior, this line would fail on compile " +"as\n" +"// x has been borrowed\n" +"// thanks to x.clone(), x was never borrowed, and this line will run.\n" msgstr "" -#: src\patterns/structural/small-crates.md:1 -msgid "# Prefer small crates" +#: src/anti_patterns/borrow_clone.md:23 +msgid "\"{x}\"" msgstr "" -#: src\patterns/structural/small-crates.md:5 -msgid "Prefer small crates that do one thing well." +#: src/anti_patterns/borrow_clone.md:24 +msgid "" +"// perform some action on the borrow to prevent rust from optimizing this\n" +"//out of existence\n" msgstr "" -#: src\patterns/structural/small-crates.md:7 -msgid "" -"Cargo and crates.io make it easy to add third-party libraries, much more so " -"than\n" -"in say C or C++. Moreover, since packages on crates.io cannot be edited or " -"removed\n" -"after publication, any build that works now should continue to work in the " -"future.\n" -"We should take advantage of this tooling, and use smaller, more fine-grained " -"dependencies." -msgstr "" - -#: src\patterns/structural/small-crates.md:14 -msgid "" -"- Small crates are easier to understand, and encourage more modular code.\n" -"- Crates allow for re-using code between projects.\n" -" For example, the `url` crate was developed as part of the Servo browser " -"engine,\n" -" but has since found wide use outside the project.\n" -"- Since the compilation unit\n" -" of Rust is the crate, splitting a project into multiple crates can allow " -"more of\n" -" the code to be built in parallel." -msgstr "" - -#: src\patterns/structural/small-crates.md:24 -msgid "" -"- This can lead to \"dependency hell\", when a project depends on multiple " -"conflicting\n" -" versions of a crate at the same time. For example, the `url` crate has " -"both versions\n" -" 1.0 and 0.5. Since the `Url` from `url:1.0` and the `Url` from `url:0.5` " -"are\n" -" different types, an HTTP client that uses `url:0.5` would not accept `Url` " -"values\n" -" from a web scraper that uses `url:1.0`.\n" -"- Packages on crates.io are not curated. A crate may be poorly written, " -"have\n" -" unhelpful documentation, or be outright malicious.\n" -"- Two small crates may be less optimized than one large one, since the " -"compiler\n" -" does not perform link-time optimization (LTO) by default." -msgstr "" - -#: src\patterns/structural/small-crates.md:36 +#: src/anti_patterns/borrow_clone.md:32 msgid "" -"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " -"functions\n" -"for converting `&T` to `&[T]`." +"It is tempting, particularly for beginners, to use this pattern to resolve " +"confusing issues with the borrow checker. However, there are serious " +"consequences. Using `.clone()` causes a copy of the data to be made. Any " +"changes between the two are not synchronized -- as if two completely " +"separate variables exist." msgstr "" -#: src\patterns/structural/small-crates.md:39 +#: src/anti_patterns/borrow_clone.md:38 msgid "" -"The [`url`](https://crates.io/crates/url) crate provides tools for working " -"with\n" -"URLs." +"There are special cases -- `Rc` is designed to handle clones " +"intelligently. It internally manages exactly one copy of the data. Invoking " +"`.clone()` on `Rc` produces a new `Rc` instance, which points to the same " +"data as the source `Rc`, while increasing a reference count. The same " +"applies to `Arc`, the thread-safe counterpart of `Rc`." msgstr "" -#: src\patterns/structural/small-crates.md:42 +#: src/anti_patterns/borrow_clone.md:44 msgid "" -"The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a " -"function to\n" -"query the number of CPUs on a machine." +"In general, clones should be deliberate, with full understanding of the " +"consequences. If a clone is used to make a borrow checker error disappear, " +"that's a good indication this anti-pattern may be in use." msgstr "" -#: src\patterns/structural/small-crates.md:47 -msgid "- [crates.io: The Rust community crate host](https://crates.io/)" +#: src/anti_patterns/borrow_clone.md:48 +msgid "" +"Even though `.clone()` is an indication of a bad pattern, sometimes **it is " +"fine to write inefficient code**, in cases such as when:" msgstr "" -#: src\patterns/structural/unsafe-mods.md:1 -msgid "# Contain unsafety in small modules" +#: src/anti_patterns/borrow_clone.md:51 +msgid "the developer is still new to ownership" msgstr "" -#: src\patterns/structural/unsafe-mods.md:5 +#: src/anti_patterns/borrow_clone.md:52 msgid "" -"If you have `unsafe` code, create the smallest possible module that can " -"uphold\n" -"the needed invariants to build a minimal safe interface upon the unsafety. " -"Embed\n" -"this into a larger module that contains only safe code and presents an " -"ergonomic\n" -"interface. Note that the outer module can contain unsafe functions and " -"methods\n" -"that call directly into the unsafe code. Users may use this to gain speed " -"benefits." +"the code doesn't have great speed or memory constraints (like hackathon " +"projects or prototypes)" msgstr "" -#: src\patterns/structural/unsafe-mods.md:13 +#: src/anti_patterns/borrow_clone.md:54 msgid "" -"- This restricts the unsafe code that must be audited\n" -"- Writing the outer module is much easier, since you can count on the " -"guarantees\n" -" of the inner module" +"satisfying the borrow checker is really complicated, and you prefer to " +"optimize readability over performance" msgstr "" -#: src\patterns/structural/unsafe-mods.md:19 +#: src/anti_patterns/borrow_clone.md:57 msgid "" -"- Sometimes, it may be hard to find a suitable interface.\n" -"- The abstraction may introduce inefficiencies." +"If an unnecessary clone is suspected, The [Rust Book's chapter on Ownership]" +"(https://doc.rust-lang.org/book/ownership.html) should be understood fully " +"before assessing whether the clone is required or not." msgstr "" -#: src\patterns/structural/unsafe-mods.md:24 +#: src/anti_patterns/borrow_clone.md:62 msgid "" -"- The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe " -"operations\n" -" in submodules, presenting a safe interface to users.\n" -"- `std`'s `String` class is a wrapper over `Vec` with the added " -"invariant\n" -" that the contents must be valid UTF-8. The operations on `String` ensure " -"this\n" -" behavior.\n" -" However, users have the option of using an `unsafe` method to create a " -"`String`,\n" -" in which case the onus is on them to guarantee the validity of the " -"contents." +"Also be sure to always run `cargo clippy` in your project, which will detect " +"some cases in which `.clone()` is not necessary." msgstr "" -#: src\patterns/structural/unsafe-mods.md:34 +#: src/anti_patterns/borrow_clone.md:67 msgid "" -"- [Ralf Jung's Blog about invariants in unsafe code](https://www.ralfj.de/" -"blog/2018/08/22/two-kinds-of-invariants.html)" -msgstr "" - -#: src\patterns/ffi/intro.md:1 -msgid "# FFI Patterns" +"[`mem::{take(_), replace(_)}` to keep owned values in changed enums](../" +"idioms/mem-replace.md)" msgstr "" -#: src\patterns/ffi/intro.md:3 +#: src/anti_patterns/borrow_clone.md:68 msgid "" -"Writing FFI code is an entire course in itself.\n" -"However, there are several idioms here that can act as pointers, and avoid " -"traps\n" -"for inexperienced users of unsafe Rust." +"[`Rc` documentation, which handles .clone() intelligently](http://" +"doc.rust-lang.org/std/rc/)" msgstr "" -#: src\patterns/ffi/intro.md:7 +#: src/anti_patterns/borrow_clone.md:69 msgid "" -"This section contains design patterns that may be useful when doing FFI." +"[`Arc` documentation, a thread-safe reference-counting pointer](https://" +"doc.rust-lang.org/std/sync/struct.Arc.html)" msgstr "" -#: src\patterns/ffi/intro.md:9 +#: src/anti_patterns/borrow_clone.md:70 msgid "" -"1. [Object-Based API](./export.md) design that has good memory safety " -"characteristics,\n" -" and a clean boundary of what is safe and what is unsafe\n" -"\n" -"2. [Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust " -"types\n" -" together into an opaque \"object\"" +"[Tricks with ownership in Rust](https://web.archive.org/web/20210120233744/" +"https://xion.io/post/code/rust-borrowchk-tricks.html)" msgstr "" -#: src\patterns/ffi/export.md:1 -msgid "# Object-Based APIs" +#: src/anti_patterns/deny-warnings.md:1 +msgid "`#![deny(warnings)]`" msgstr "" -#: src\patterns/ffi/export.md:5 +#: src/anti_patterns/deny-warnings.md:5 msgid "" -"When designing APIs in Rust which are exposed to other languages, there are " -"some\n" -"important design principles which are contrary to normal Rust API design:" +"A well-intentioned crate author wants to ensure their code builds without " +"warnings. So they annotate their crate root with the following:" msgstr "" -#: src\patterns/ffi/export.md:8 -msgid "" -"1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user,\n" -" and _opaque_.\n" -"2. All Transactional data types should be _owned_ by the user, and " -"_transparent_.\n" -"3. All library behavior should be functions acting upon Encapsulated types.\n" -"4. All library behavior should be encapsulated into types not based on " -"structure,\n" -" but _provenance/lifetime_." +#: src/anti_patterns/deny-warnings.md:12 +msgid "// All is well.\n" msgstr "" -#: src\patterns/ffi/export.md:17 -msgid "" -"Rust has built-in FFI support to other languages.\n" -"It does this by providing a way for crate authors to provide C-compatible " -"APIs\n" -"through different ABIs (though that is unimportant to this practice)." +#: src/anti_patterns/deny-warnings.md:18 +msgid "It is short and will stop the build if anything is amiss." msgstr "" -#: src\patterns/ffi/export.md:21 -msgid "" -"Well-designed Rust FFI follows C API design principles, while compromising " -"the\n" -"design in Rust as little as possible. There are three goals with any foreign " -"API:" +#: src/anti_patterns/deny-warnings.md:20 +msgid "Drawbacks" msgstr "" -#: src\patterns/ffi/export.md:24 +#: src/anti_patterns/deny-warnings.md:22 msgid "" -"1. Make it easy to use in the target language.\n" -"2. Avoid the API dictating internal unsafety on the Rust side as much as " -"possible.\n" -"3. Keep the potential for memory unsafety and Rust `undefined behaviour` as " -"small\n" -" as possible." +"By disallowing the compiler to build with warnings, a crate author opts out " +"of Rust's famed stability. Sometimes new features or old misfeatures need a " +"change in how things are done, thus lints are written that `warn` for a " +"certain grace period before being turned to `deny`." msgstr "" -#: src\patterns/ffi/export.md:29 +#: src/anti_patterns/deny-warnings.md:27 msgid "" -"Rust code must trust the memory safety of the foreign language beyond a " -"certain\n" -"point. However, every bit of `unsafe` code on the Rust side is an " -"opportunity for\n" -"bugs, or to exacerbate `undefined behaviour`." +"For example, it was discovered that a type could have two `impl`s with the " +"same method. This was deemed a bad idea, but in order to make the transition " +"smooth, the `overlapping-inherent-impls` lint was introduced to give a " +"warning to those stumbling on this fact, before it becomes a hard error in a " +"future release." msgstr "" -#: src\patterns/ffi/export.md:33 +#: src/anti_patterns/deny-warnings.md:32 msgid "" -"For example, if a pointer provenance is wrong, that may be a segfault due " -"to\n" -"invalid memory access. But if it is manipulated by unsafe code, it could " -"become\n" -"full-blown heap corruption." +"Also sometimes APIs get deprecated, so their use will emit a warning where " +"before there was none." msgstr "" -#: src\patterns/ffi/export.md:37 +#: src/anti_patterns/deny-warnings.md:35 msgid "" -"The Object-Based API design allows for writing shims that have good memory " -"safety\n" -"characteristics, and a clean boundary of what is safe and what is `unsafe`." +"All this conspires to potentially break the build whenever something changes." msgstr "" -#: src\patterns/ffi/export.md:42 +#: src/anti_patterns/deny-warnings.md:37 msgid "" -"The POSIX standard defines the API to access an on-file database, known as " -"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/" -"ndbm.h).\n" -"It is an excellent example of an \"object-based\" API." +"Furthermore, crates that supply additional lints (e.g. [rust-clippy](https://" +"github.com/rust-lang/rust-clippy)) can no longer be used unless the " +"annotation is removed. This is mitigated with [\\--cap-lints](https://" +"doc.rust-lang.org/rustc/lints/levels.html#capping-lints). The `--cap-" +"lints=warn` command line argument, turns all `deny` lint errors into " +"warnings." msgstr "" -#: src\patterns/ffi/export.md:45 -msgid "" -"Here is the definition in C, which hopefully should be easy to read for " -"those\n" -"involved in FFI. The commentary below should help explain it for those who\n" -"miss the subtleties." +#: src/anti_patterns/deny-warnings.md:42 +#: src/functional/generics-type-classes.md:226 +msgid "Alternatives" msgstr "" -#: src\patterns/ffi/export.md:49 +#: src/anti_patterns/deny-warnings.md:44 msgid "" -"```C\n" -"struct DBM;\n" -"typedef struct { void *dptr, size_t dsize } datum;\n" -"\n" -"int dbm_clearerr(DBM *);\n" -"void dbm_close(DBM *);\n" -"int dbm_delete(DBM *, datum);\n" -"int dbm_error(DBM *);\n" -"datum dbm_fetch(DBM *, datum);\n" -"datum dbm_firstkey(DBM *);\n" -"datum dbm_nextkey(DBM *);\n" -"DBM *dbm_open(const char *, int, mode_t);\n" -"int dbm_store(DBM *, datum, datum, int);\n" -"```" +"There are two ways of tackling this problem: First, we can decouple the " +"build setting from the code, and second, we can name the lints we want to " +"deny explicitly." msgstr "" -#: src\patterns/ffi/export.md:64 -msgid "This API defines two types: `DBM` and `datum`." +#: src/anti_patterns/deny-warnings.md:48 +msgid "The following command line will build with all warnings set to `deny`:" msgstr "" -#: src\patterns/ffi/export.md:66 -msgid "" -"The `DBM` type was called an \"encapsulated\" type above.\n" -"It is designed to contain internal state, and acts as an entry point for " -"the\n" -"library's behavior." +#: src/anti_patterns/deny-warnings.md:50 +msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" msgstr "" -#: src\patterns/ffi/export.md:70 +#: src/anti_patterns/deny-warnings.md:52 msgid "" -"It is completely opaque to the user, who cannot create a `DBM` themselves " -"since\n" -"they don't know its size or layout. Instead, they must call `dbm_open`, and " -"that\n" -"only gives them _a pointer to one_." +"This can be done by any individual developer (or be set in a CI tool like " +"Travis, but remember that this may break the build when something changes) " +"without requiring a change to the code." msgstr "" -#: src\patterns/ffi/export.md:74 +#: src/anti_patterns/deny-warnings.md:56 msgid "" -"This means all `DBM`s are \"owned\" by the library in a Rust sense.\n" -"The internal state of unknown size is kept in memory controlled by the " -"library,\n" -"not the user. The user can only manage its life cycle with `open` and " -"`close`,\n" -"and perform operations on it with the other functions." +"Alternatively, we can specify the lints that we want to `deny` in the code. " +"Here is a list of warning lints that is (hopefully) safe to deny (as of " +"rustc 1.48.0):" msgstr "" -#: src\patterns/ffi/export.md:79 +#: src/anti_patterns/deny-warnings.md:81 msgid "" -"The `datum` type was called a \"transactional\" type above.\n" -"It is designed to facilitate the exchange of information between the library " -"and\n" -"its user." +"In addition, the following `allow`ed lints may be a good idea to `deny`:" msgstr "" -#: src\patterns/ffi/export.md:83 -msgid "" -"The database is designed to store \"unstructured data\", with no pre-defined " -"length\n" -"or meaning. As a result, the `datum` is the C equivalent of a Rust slice: a " -"bunch\n" -"of bytes, and a count of how many there are. The main difference is that " -"there is\n" -"no type information, which is what `void` indicates." +#: src/anti_patterns/deny-warnings.md:96 +msgid "Some may also want to add `missing-copy-implementations` to their list." msgstr "" -#: src\patterns/ffi/export.md:88 +#: src/anti_patterns/deny-warnings.md:98 msgid "" -"Keep in mind that this header is written from the library's point of view.\n" -"The user likely has some type they are using, which has a known size.\n" -"But the library does not care, and by the rules of C casting, any type " -"behind a\n" -"pointer can be cast to `void`." +"Note that we explicitly did not add the `deprecated` lint, as it is fairly " +"certain that there will be more deprecated APIs in the future." msgstr "" -#: src\patterns/ffi/export.md:93 +#: src/anti_patterns/deny-warnings.md:103 msgid "" -"As noted earlier, this type is _transparent_ to the user. But also, this " -"type is\n" -"_owned_ by the user.\n" -"This has subtle ramifications, due to that pointer inside it.\n" -"The question is, who owns the memory that pointer points to?" +"[A collection of all clippy lints](https://rust-lang.github.io/rust-clippy/" +"master)" msgstr "" -#: src\patterns/ffi/export.md:98 +#: src/anti_patterns/deny-warnings.md:104 msgid "" -"The answer for best memory safety is, \"the user\".\n" -"But in cases such as retrieving a value, the user does not know how to " -"allocate\n" -"it correctly (since they don't know how long the value is). In this case, " -"the library\n" -"code is expected to use the heap that the user has access to -- such as the " -"C library\n" -"`malloc` and `free` -- and then _transfer ownership_ in the Rust sense." +"[deprecate attribute](https://doc.rust-lang.org/reference/" +"attributes.html#deprecation) documentation" msgstr "" -#: src\patterns/ffi/export.md:104 +#: src/anti_patterns/deny-warnings.md:105 msgid "" -"This may all seem speculative, but this is what a pointer means in C.\n" -"It means the same thing as Rust: \"user defined lifetime.\"\n" -"The user of the library needs to read the documentation in order to use it " -"correctly.\n" -"That said, there are some decisions that have fewer or greater consequences " -"if users\n" -"do it wrong. Minimizing those are what this best practice is about, and the " -"key\n" -"is to _transfer ownership of everything that is transparent_." +"Type `rustc -W help` for a list of lints on your system. Also type `rustc --" +"help` for a general list of options" msgstr "" -#: src\patterns/ffi/export.md:113 +#: src/anti_patterns/deny-warnings.md:107 msgid "" -"This minimizes the number of memory safety guarantees the user must uphold " -"to a\n" -"relatively small number:" +"[rust-clippy](https://github.com/rust-lang/rust-clippy) is a collection of " +"lints for better Rust code" msgstr "" -#: src\patterns/ffi/export.md:116 -msgid "" -"1. Do not call any function with a pointer not returned by `dbm_open` " -"(invalid\n" -" access or corruption).\n" -"2. Do not call any function on a pointer after close (use after free).\n" -"3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of " -"memory\n" -" at the advertised length." +#: src/anti_patterns/deref.md:1 +msgid "`Deref` polymorphism" msgstr "" -#: src\patterns/ffi/export.md:122 +#: src/anti_patterns/deref.md:5 msgid "" -"In addition, it avoids a lot of pointer provenance issues.\n" -"To understand why, let us consider an alternative in some depth: key " -"iteration." +"Misuse the `Deref` trait to emulate inheritance between structs, and thus " +"reuse methods." msgstr "" -#: src\patterns/ffi/export.md:125 +#: src/anti_patterns/deref.md:10 msgid "" -"Rust is well known for its iterators.\n" -"When implementing one, the programmer makes a separate type with a bounded " -"lifetime\n" -"to its owner, and implements the `Iterator` trait." +"Sometimes we want to emulate the following common pattern from OO languages " +"such as Java:" msgstr "" -#: src\patterns/ffi/export.md:129 -msgid "Here is how iteration would be done in Rust for `DBM`:" +#: src/anti_patterns/deref.md:26 +msgid "We can use the deref polymorphism anti-pattern to do so:" msgstr "" -#: src\patterns/ffi/export.md:131 +#: src/anti_patterns/deref.md:56 msgid "" -"```rust,ignore\n" -"struct Dbm { ... }\n" -"\n" -"impl Dbm {\n" -" /* ... */\n" -" pub fn keys<'it>(&'it self) -> DbmKeysIter<'it> { ... }\n" -" /* ... */\n" -"}\n" -"\n" -"struct DbmKeysIter<'it> {\n" -" owner: &'it Dbm,\n" -"}\n" -"\n" -"impl<'it> Iterator for DbmKeysIter<'it> { ... }\n" -"```" -msgstr "" - -#: src\patterns/ffi/export.md:147 -msgid "" -"This is clean, idiomatic, and safe. thanks to Rust's guarantees.\n" -"However, consider what a straightforward API translation would look like:" -msgstr "" - -#: src\patterns/ffi/export.md:150 -msgid "" -"```rust,ignore\n" -"#[no_mangle]\n" -"pub extern \"C\" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter {\n" -" // THIS API IS A BAD IDEA! For real applications, use object-based " -"design instead.\n" -"}\n" -"#[no_mangle]\n" -"pub extern \"C\" fn dbm_iter_next(\n" -" iter: *mut DbmKeysIter,\n" -" key_out: *const datum\n" -") -> libc::c_int {\n" -" // THIS API IS A BAD IDEA! For real applications, use object-based " -"design instead.\n" -"}\n" -"#[no_mangle]\n" -"pub extern \"C\" fn dbm_iter_del(*mut DbmKeysIter) {\n" -" // THIS API IS A BAD IDEA! For real applications, use object-based " -"design instead.\n" -"}\n" -"```" +"There is no struct inheritance in Rust. Instead we use composition and " +"include an instance of `Foo` in `Bar` (since the field is a value, it is " +"stored inline, so if there were fields, they would have the same layout in " +"memory as the Java version (probably, you should use `#[repr(C)]` if you " +"want to be sure))." msgstr "" -#: src\patterns/ffi/export.md:168 +#: src/anti_patterns/deref.md:61 msgid "" -"This API loses a key piece of information: the lifetime of the iterator must " -"not\n" -"exceed the lifetime of the `Dbm` object that owns it. A user of the library " -"could\n" -"use it in a way which causes the iterator to outlive the data it is " -"iterating on,\n" -"resulting in reading uninitialized memory." +"In order to make the method call work we implement `Deref` for `Bar` with " +"`Foo` as the target (returning the embedded `Foo` field). That means that " +"when we dereference a `Bar` (for example, using `*`) then we will get a " +"`Foo`. That is pretty weird. Dereferencing usually gives a `T` from a " +"reference to `T`, here we have two unrelated types. However, since the dot " +"operator does implicit dereferencing, it means that the method call will " +"search for methods on `Foo` as well as `Bar`." msgstr "" -#: src\patterns/ffi/export.md:173 -msgid "" -"This example written in C contains a bug that will be explained afterwards:" +#: src/anti_patterns/deref.md:71 +msgid "You save a little boilerplate, e.g.," msgstr "" -#: src\patterns/ffi/export.md:175 +#: src/anti_patterns/deref.md:83 msgid "" -"```C\n" -"int count_key_sizes(DBM *db) {\n" -" // DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG!\n" -" datum key;\n" -" int len = 0;\n" -"\n" -" if (!dbm_iter_new(db)) {\n" -" dbm_close(db);\n" -" return -1;\n" -" }\n" -"\n" -" int l;\n" -" while ((l = dbm_iter_next(owner, &key)) >= 0) { // an error is indicated " -"by -1\n" -" free(key.dptr);\n" -" len += key.dsize;\n" -" if (l == 0) { // end of the iterator\n" -" dbm_close(owner);\n" -" }\n" -" }\n" -" if l >= 0 {\n" -" return -1;\n" -" } else {\n" -" return len;\n" -" }\n" -"}\n" -"```" +"Most importantly this is a surprising idiom - future programmers reading " +"this in code will not expect this to happen. That's because we are misusing " +"the `Deref` trait rather than using it as intended (and documented, etc.). " +"It's also because the mechanism here is completely implicit." msgstr "" -#: src\patterns/ffi/export.md:202 +#: src/anti_patterns/deref.md:88 msgid "" -"This bug is a classic. Here's what happens when the iterator returns the\n" -"end-of-iteration marker:" +"This pattern does not introduce subtyping between `Foo` and `Bar` like " +"inheritance in Java or C++ does. Furthermore, traits implemented by `Foo` " +"are not automatically implemented for `Bar`, so this pattern interacts badly " +"with bounds checking and thus generic programming." msgstr "" -#: src\patterns/ffi/export.md:205 +#: src/anti_patterns/deref.md:93 msgid "" -"1. The loop condition sets `l` to zero, and enters the loop because `0 >= " -"0`.\n" -"2. The length is incremented, in this case by zero.\n" -"3. The if statement is true, so the database is closed. There should be a " -"break\n" -" statement here.\n" -"4. The loop condition executes again, causing a `next` call on the closed " -"object." +"Using this pattern gives subtly different semantics from most OO languages " +"with regards to `self`. Usually it remains a reference to the sub-class, " +"with this pattern it will be the 'class' where the method is defined." msgstr "" -#: src\patterns/ffi/export.md:211 +#: src/anti_patterns/deref.md:97 msgid "" -"The worst part about this bug?\n" -"If the Rust implementation was careful, this code will work most of the " -"time!\n" -"If the memory for the `Dbm` object is not immediately reused, an internal " -"check\n" -"will almost certainly fail, resulting in the iterator returning a `-1` " -"indicating\n" -"an error. But occasionally, it will cause a segmentation fault, or even " -"worse,\n" -"nonsensical memory corruption!" +"Finally, this pattern only supports single inheritance, and has no notion of " +"interfaces, class-based privacy, or other inheritance-related features. So, " +"it gives an experience that will be subtly surprising to programmers used to " +"Java inheritance, etc." msgstr "" -#: src\patterns/ffi/export.md:218 +#: src/anti_patterns/deref.md:104 msgid "" -"None of this can be avoided by Rust.\n" -"From its perspective, it put those objects on its heap, returned pointers to " -"them,\n" -"and gave up control of their lifetimes. The C code simply must \"play nice\"." +"There is no one good alternative. Depending on the exact circumstances it " +"might be better to re-implement using traits or to write out the facade " +"methods to dispatch to `Foo` manually. We do intend to add a mechanism for " +"inheritance similar to this to Rust, but it is likely to be some time before " +"it reaches stable Rust. See these [blog](http://aturon.github.io/blog/" +"2015/09/18/reuse/) [posts](http://smallcultfollowing.com/babysteps/blog/" +"2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/) and this " +"[RFC issue](https://github.com/rust-lang/rfcs/issues/349) for more details." msgstr "" -#: src\patterns/ffi/export.md:222 +#: src/anti_patterns/deref.md:113 msgid "" -"The programmer must read and understand the API documentation.\n" -"While some consider that par for the course in C, a good API design can " -"mitigate\n" -"this risk. The POSIX API for `DBM` did this by _consolidating the ownership_ " -"of\n" -"the iterator with its parent:" +"The `Deref` trait is designed for the implementation of custom pointer " +"types. The intention is that it will take a pointer-to-`T` to a `T`, not " +"convert between different types. It is a shame that this isn't (probably " +"cannot be) enforced by the trait definition." msgstr "" -#: src\patterns/ffi/export.md:227 +#: src/anti_patterns/deref.md:118 msgid "" -"```C\n" -"datum dbm_firstkey(DBM *);\n" -"datum dbm_nextkey(DBM *);\n" -"```" +"Rust tries to strike a careful balance between explicit and implicit " +"mechanisms, favouring explicit conversions between types. Automatic " +"dereferencing in the dot operator is a case where the ergonomics strongly " +"favour an implicit mechanism, but the intention is that this is limited to " +"degrees of indirection, not conversion between arbitrary types." msgstr "" -#: src\patterns/ffi/export.md:232 +#: src/anti_patterns/deref.md:126 +#, fuzzy +msgid "[Collections are smart pointers idiom](../idioms/deref.md)." +msgstr "コレクションはスマートポインタである" + +#: src/anti_patterns/deref.md:127 msgid "" -"Thus, all the lifetimes were bound together, and such unsafety was prevented." +"Delegation crates for less boilerplate like [delegate](https://crates.io/" +"crates/delegate) or [ambassador](https://crates.io/crates/ambassador)" msgstr "" -#: src\patterns/ffi/export.md:236 -msgid "" -"However, this design choice also has a number of drawbacks, which should be\n" -"considered as well." +#: src/functional/index.md:1 +msgid "Functional Usage of Rust" msgstr "" -#: src\patterns/ffi/export.md:239 +#: src/functional/index.md:3 msgid "" -"First, the API itself becomes less expressive.\n" -"With POSIX DBM, there is only one iterator per object, and every call " -"changes\n" -"its state. This is much more restrictive than iterators in almost any " -"language,\n" -"even though it is safe. Perhaps with other related objects, whose lifetimes " -"are\n" -"less hierarchical, this limitation is more of a cost than the safety." +"Rust is an imperative language, but it follows many [functional programming]" +"(https://en.wikipedia.org/wiki/Functional_programming) paradigms." msgstr "" -#: src\patterns/ffi/export.md:245 +#: src/functional/index.md:7 msgid "" -"Second, depending on the relationships of the API's parts, significant " -"design effort\n" -"may be involved. Many of the easier design points have other patterns " -"associated\n" -"with them:" +"In computer science, _functional programming_ is a programming paradigm " +"where programs are constructed by applying and composing functions. It is a " +"declarative programming paradigm in which function definitions are trees of " +"expressions that each return a value, rather than a sequence of imperative " +"statements which change the state of the program." msgstr "" -#: src\patterns/ffi/export.md:249 +#: src/functional/paradigms.md:3 msgid "" -"- [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types " -"together\n" -" into an opaque \"object\"\n" -"\n" -"- [FFI Error Passing](../../idioms/ffi/errors.md) explains error handling " -"with integer\n" -" codes and sentinel return values (such as `NULL` pointers)\n" -"\n" -"- [Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) allows " -"accepting\n" -" strings with minimal unsafe code, and is easier to get right than\n" -" [Passing Strings to FFI](../../idioms/ffi/passing-strings.md)" +"One of the biggest hurdles to understanding functional programs when coming " +"from an imperative background is the shift in thinking. Imperative programs " +"describe **how** to do something, whereas declarative programs describe " +"**what** to do. Let's sum the numbers from 1 to 10 to show this." msgstr "" -#: src\patterns/ffi/export.md:259 -msgid "" -"However, not every API can be done this way.\n" -"It is up to the best judgement of the programmer as to who their audience is." +#: src/functional/paradigms.md:8 +msgid "Imperative" msgstr "" -#: src\patterns/ffi/wrappers.md:1 -msgid "# Type Consolidation into Wrappers" +#: src/functional/paradigms.md:15 +msgid "\"{sum}\"" msgstr "" -#: src\patterns/ffi/wrappers.md:5 +#: src/functional/paradigms.md:18 msgid "" -"This pattern is designed to allow gracefully handling multiple related " -"types,\n" -"while minimizing the surface area for memory unsafety." +"With imperative programs, we have to play compiler to see what is happening. " +"Here, we start with a `sum` of `0`. Next, we iterate through the range from " +"1 to 10. Each time through the loop, we add the corresponding value in the " +"range. Then we print it out." msgstr "" -#: src\patterns/ffi/wrappers.md:8 -msgid "" -"One of the cornerstones of Rust's aliasing rules is lifetimes.\n" -"This ensures that many patterns of access between types can be memory safe,\n" -"data race safety included." +#: src/functional/paradigms.md:23 +msgid "`i`" msgstr "" -#: src\patterns/ffi/wrappers.md:12 -msgid "" -"However, when Rust types are exported to other languages, they are usually " -"transformed\n" -"into pointers. In Rust, a pointer means \"the user manages the lifetime of " -"the pointee.\"\n" -"It is their responsibility to avoid memory unsafety." +#: src/functional/paradigms.md:23 +msgid "`sum`" msgstr "" -#: src\patterns/ffi/wrappers.md:16 -msgid "" -"Some level of trust in the user code is thus required, notably around use-" -"after-free\n" -"which Rust can do nothing about. However, some API designs place higher " -"burdens\n" -"than others on the code written in the other language." +#: src/functional/paradigms.md:25 src/functional/paradigms.md:59 +#: src/functional/paradigms.md:60 +msgid "1" msgstr "" -#: src\patterns/ffi/wrappers.md:20 -msgid "" -"The lowest risk API is the \"consolidated wrapper\", where all possible " -"interactions\n" -"with an object are folded into a \"wrapper type\", while keeping the Rust " -"API clean." +#: src/functional/paradigms.md:26 src/functional/paradigms.md:60 +msgid "2" msgstr "" -#: src\patterns/ffi/wrappers.md:25 -msgid "" -"To understand this, let us look at a classic example of an API to export: " -"iteration\n" -"through a collection." +#: src/functional/paradigms.md:26 src/functional/paradigms.md:27 +#: src/functional/paradigms.md:60 src/functional/paradigms.md:61 +msgid "3" msgstr "" -#: src\patterns/ffi/wrappers.md:28 -msgid "That API looks like this:" +#: src/functional/paradigms.md:27 src/functional/paradigms.md:30 +#: src/functional/paradigms.md:61 src/functional/paradigms.md:62 +#: src/functional/paradigms.md:64 +msgid "6" msgstr "" -#: src\patterns/ffi/wrappers.md:30 -msgid "" -"1. The iterator is initialized with `first_key`.\n" -"2. Each call to `next_key` will advance the iterator.\n" -"3. Calls to `next_key` if the iterator is at the end will do nothing.\n" -"4. As noted above, the iterator is \"wrapped into\" the collection (unlike " -"the native\n" -" Rust API)." +#: src/functional/paradigms.md:28 src/functional/paradigms.md:62 +msgid "4" msgstr "" -#: src\patterns/ffi/wrappers.md:36 -msgid "" -"If the iterator implements `nth()` efficiently, then it is possible to make " -"it\n" -"ephemeral to each function call:" +#: src/functional/paradigms.md:28 src/functional/paradigms.md:34 +#: src/functional/paradigms.md:62 src/functional/paradigms.md:63 +#: src/functional/paradigms.md:68 +msgid "10" msgstr "" -#: src\patterns/ffi/wrappers.md:39 -msgid "" -"```rust,ignore\n" -"struct MySetWrapper {\n" -" myset: MySet,\n" -" iter_next: usize,\n" -"}\n" -"\n" -"impl MySetWrapper {\n" -" pub fn first_key(&mut self) -> Option<&Key> {\n" -" self.iter_next = 0;\n" -" self.next_key()\n" -" }\n" -" pub fn next_key(&mut self) -> Option<&Key> {\n" -" if let Some(next) = self.myset.keys().nth(self.iter_next) {\n" -" self.iter_next += 1;\n" -" Some(next)\n" -" } else {\n" -" None\n" -" }\n" -" }\n" -"}\n" -"```" +#: src/functional/paradigms.md:29 src/functional/paradigms.md:63 +msgid "5" msgstr "" -#: src\patterns/ffi/wrappers.md:61 -msgid "As a result, the wrapper is simple and contains no `unsafe` code." +#: src/functional/paradigms.md:29 src/functional/paradigms.md:63 +#: src/functional/paradigms.md:64 +msgid "15" msgstr "" -#: src\patterns/ffi/wrappers.md:65 -msgid "" -"This makes APIs safer to use, avoiding issues with lifetimes between types.\n" -"See [Object-Based APIs](./export.md) for more on the advantages and " -"pitfalls\n" -"this avoids." +#: src/functional/paradigms.md:30 src/functional/paradigms.md:64 +#: src/functional/paradigms.md:65 +msgid "21" msgstr "" -#: src\patterns/ffi/wrappers.md:71 -msgid "" -"Often, wrapping types is quite difficult, and sometimes a Rust API " -"compromise\n" -"would make things easier." +#: src/functional/paradigms.md:31 src/functional/paradigms.md:65 +msgid "7" msgstr "" -#: src\patterns/ffi/wrappers.md:74 -msgid "" -"As an example, consider an iterator which does not efficiently implement " -"`nth()`.\n" -"It would definitely be worth putting in special logic to make the object " -"handle\n" -"iteration internally, or to support a different access pattern efficiently " -"that\n" -"only the Foreign Function API will use." +#: src/functional/paradigms.md:31 src/functional/paradigms.md:65 +#: src/functional/paradigms.md:66 +msgid "28" msgstr "" -#: src\patterns/ffi/wrappers.md:79 -msgid "### Trying to Wrap Iterators (and Failing)" +#: src/functional/paradigms.md:32 src/functional/paradigms.md:66 +msgid "8" msgstr "" -#: src\patterns/ffi/wrappers.md:81 -msgid "" -"To wrap any type of iterator into the API correctly, the wrapper would need " -"to\n" -"do what a C version of the code would do: erase the lifetime of the " -"iterator,\n" -"and manage it manually." +#: src/functional/paradigms.md:32 src/functional/paradigms.md:66 +#: src/functional/paradigms.md:67 +msgid "36" msgstr "" -#: src\patterns/ffi/wrappers.md:85 -msgid "Suffice it to say, this is _incredibly_ difficult." +#: src/functional/paradigms.md:33 src/functional/paradigms.md:67 +msgid "9" msgstr "" -#: src\patterns/ffi/wrappers.md:87 -msgid "Here is an illustration of just _one_ pitfall." +#: src/functional/paradigms.md:33 src/functional/paradigms.md:67 +#: src/functional/paradigms.md:68 +msgid "45" msgstr "" -#: src\patterns/ffi/wrappers.md:89 -msgid "A first version of `MySetWrapper` would look like this:" +#: src/functional/paradigms.md:34 src/functional/paradigms.md:68 +msgid "55" msgstr "" -#: src\patterns/ffi/wrappers.md:91 +#: src/functional/paradigms.md:36 msgid "" -"```rust,ignore\n" -"struct MySetWrapper {\n" -" myset: MySet,\n" -" iter_next: usize,\n" -" // created from a transmuted Box\n" -" iterator: Option>>,\n" -"}\n" -"```" +"This is how most of us start out programming. We learn that a program is a " +"set of steps." +msgstr "" + +#: src/functional/paradigms.md:39 +msgid "Declarative" msgstr "" -#: src\patterns/ffi/wrappers.md:100 +#: src/functional/paradigms.md:42 +msgid "\"{}\"" +msgstr "" + +#: src/functional/paradigms.md:45 msgid "" -"With `transmute` being used to extend a lifetime, and a pointer to hide it,\n" -"it's ugly already. But it gets even worse: _any other operation can cause\n" -"Rust `undefined behaviour`_." +"Whoa! This is really different! What's going on here? Remember that with " +"declarative programs we are describing **what** to do, rather than **how** " +"to do it. `fold` is a function that [composes](https://en.wikipedia.org/wiki/" +"Function_composition) functions. The name is a convention from Haskell." msgstr "" -#: src\patterns/ffi/wrappers.md:104 +#: src/functional/paradigms.md:51 msgid "" -"Consider that the `MySet` in the wrapper could be manipulated by other\n" -"functions during iteration, such as storing a new value to the key it was\n" -"iterating over. The API doesn't discourage this, and in fact some similar C\n" -"libraries expect it." +"Here, we are composing functions of addition (this closure: `|a, b| a + b`) " +"with a range from 1 to 10. The `0` is the starting point, so `a` is `0` at " +"first. `b` is the first element of the range, `1`. `0 + 1 = 1` is the " +"result. So now we `fold` again, with `a = 1`, `b = 2` and so `1 + 2 = 3` is " +"the next result. This process continues until we get to the last element in " +"the range, `10`." msgstr "" -#: src\patterns/ffi/wrappers.md:109 -msgid "A simple implementation of `myset_store` would be:" +#: src/functional/paradigms.md:57 +msgid "`a`" msgstr "" -#: src\patterns/ffi/wrappers.md:111 -msgid "" -"```rust,ignore\n" -"pub mod unsafe_module {\n" -"\n" -" // other module content\n" -"\n" -" pub fn myset_store(\n" -" myset: *mut MySetWrapper,\n" -" key: datum,\n" -" value: datum) -> libc::c_int {\n" -"\n" -" // DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM.\n" -"\n" -" let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in " -"here!\n" -" &mut (*myset).myset\n" -" };\n" -"\n" -" /* ...check and cast key and value data... */\n" -"\n" -" match myset.store(casted_key, casted_value) {\n" -" Ok(_) => 0,\n" -" Err(e) => e.into()\n" -" }\n" -" }\n" -"}\n" -"```" +#: src/functional/paradigms.md:57 +msgid "`b`" msgstr "" -#: src\patterns/ffi/wrappers.md:137 -msgid "" -"If the iterator exists when this function is called, we have violated one of " -"Rust's\n" -"aliasing rules. According to Rust, the mutable reference in this block must " -"have\n" -"_exclusive_ access to the object. If the iterator simply exists, it's not " -"exclusive,\n" -"so we have `undefined behaviour`! " +#: src/functional/paradigms.md:57 +msgid "result" msgstr "" -#: src\patterns/ffi/wrappers.md:142 -msgid "" -"To avoid this, we must have a way of ensuring that mutable reference really " -"is exclusive.\n" -"That basically means clearing out the iterator's shared reference while it " -"exists,\n" -"and then reconstructing it. In most cases, that will still be less efficient " -"than\n" -"the C version." +#: src/functional/paradigms.md:59 +msgid "0" msgstr "" -#: src\patterns/ffi/wrappers.md:147 +#: src/functional/generics-type-classes.md:5 msgid "" -"Some may ask: how can C do this more efficiently?\n" -"The answer is, it cheats. Rust's aliasing rules are the problem, and C " -"simply ignores\n" -"them for its pointers. In exchange, it is common to see code that is " -"declared\n" -"in the manual as \"not thread safe\" under some or all circumstances. In " -"fact,\n" -"the [GNU C library](https://manpages.debian.org/buster/manpages/" -"attributes.7.en.html)\n" -"has an entire lexicon dedicated to concurrent behavior!" +"Rust's type system is designed more like functional languages (like Haskell) " +"rather than imperative languages (like Java and C++). As a result, Rust can " +"turn many kinds of programming problems into \"static typing\" problems. " +"This is one of the biggest wins of choosing a functional language, and is " +"critical to many of Rust's compile time guarantees." msgstr "" -#: src\patterns/ffi/wrappers.md:154 +#: src/functional/generics-type-classes.md:11 msgid "" -"Rust would rather make everything memory safe all the time, for both safety " -"and\n" -"optimizations that C code cannot attain. Being denied access to certain " -"shortcuts\n" -"is the price Rust programmers need to pay." +"A key part of this idea is the way generic types work. In C++ and Java, for " +"example, generic types are a meta-programming construct for the compiler. " +"`vector` and `vector` in C++ are just two different copies of the " +"same boilerplate code for a `vector` type (known as a `template`) with two " +"different types filled in." msgstr "" -#: src\patterns/ffi/wrappers.md:158 +#: src/functional/generics-type-classes.md:17 msgid "" -"For the C programmers out there scratching their heads, the iterator need\n" -"not be read _during_ this code cause the UB. The exclusivity rule also " -"enables\n" -"compiler optimizations which may cause inconsistent observations by the " -"iterator's\n" -"shared reference (e.g. stack spills or reordering instructions for " -"efficiency).\n" -"These observations may happen _any time after_ the mutable reference is " -"created." +"In Rust, a generic type parameter creates what is known in functional " +"languages as a \"type class constraint\", and each different parameter " +"filled in by an end user _actually changes the type_. In other words, " +"`Vec` and `Vec` _are two different types_, which are recognized " +"as distinct by all parts of the type system." msgstr "" -#: src\anti_patterns/index.md:1 -msgid "# Anti-patterns" +#: src/functional/generics-type-classes.md:23 +msgid "" +"This is called **monomorphization**, where different types are created from " +"**polymorphic** code. This special behavior requires `impl` blocks to " +"specify generic parameters. Different values for the generic type cause " +"different types, and different types can have different `impl` blocks." msgstr "" -#: src\anti_patterns/index.md:3 +#: src/functional/generics-type-classes.md:28 msgid "" -"An [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern) is a solution " -"to\n" -"a \"recurring problem that is usually ineffective and risks being highly\n" -"counterproductive\". Just as valuable as knowing how to solve a problem, is\n" -"knowing how _not_ to solve it. Anti-patterns give us great counter-examples " -"to\n" -"consider relative to design patterns. Anti-patterns are not confined to " -"code.\n" -"For example, a process can be an anti-pattern, too." +"In object-oriented languages, classes can inherit behavior from their " +"parents. However, this allows the attachment of not only additional behavior " +"to particular members of a type class, but extra behavior as well." msgstr "" -#: src\anti_patterns/borrow_clone.md:1 -msgid "# Clone to satisfy the borrow checker" +#: src/functional/generics-type-classes.md:32 +msgid "" +"The nearest equivalent is the runtime polymorphism in Javascript and Python, " +"where new members can be added to objects willy-nilly by any constructor. " +"However, unlike those languages, all of Rust's additional methods can be " +"type checked when they are used, because their generics are statically " +"defined. That makes them more usable while remaining safe." msgstr "" -#: src\anti_patterns/borrow_clone.md:5 +#: src/functional/generics-type-classes.md:40 msgid "" -"The borrow checker prevents Rust users from developing otherwise unsafe code " -"by\n" -"ensuring that either: only one mutable reference exists, or potentially many " -"but\n" -"all immutable references exist. If the code written does not hold true to " -"these\n" -"conditions, this anti-pattern arises when the developer resolves the " -"compiler\n" -"error by cloning the variable." +"Suppose you are designing a storage server for a series of lab machines. " +"Because of the software involved, there are two different protocols you need " +"to support: BOOTP (for PXE network boot), and NFS (for remote mount storage)." msgstr "" -#: src\anti_patterns/borrow_clone.md:13 +#: src/functional/generics-type-classes.md:44 msgid "" -"```rust\n" -"// define any variable\n" -"let mut x = 5;\n" -"\n" -"// Borrow `x` -- but clone it first\n" -"let y = &mut (x.clone());\n" -"\n" -"// without the x.clone() two lines prior, this line would fail on compile " -"as\n" -"// x has been borrowed\n" -"// thanks to x.clone(), x was never borrowed, and this line will run.\n" -"println!(\"{}\", x);\n" -"\n" -"// perform some action on the borrow to prevent rust from optimizing this\n" -"//out of existence\n" -"*y += 1;\n" -"```" +"Your goal is to have one program, written in Rust, which can handle both of " +"them. It will have protocol handlers and listen for both kinds of requests. " +"The main application logic will then allow a lab administrator to configure " +"storage and security controls for the actual files." msgstr "" -#: src\anti_patterns/borrow_clone.md:32 +#: src/functional/generics-type-classes.md:49 msgid "" -"It is tempting, particularly for beginners, to use this pattern to resolve\n" -"confusing issues with the borrow checker. However, there are serious\n" -"consequences. Using `.clone()` causes a copy of the data to be made. Any " -"changes\n" -"between the two are not synchronized -- as if two completely separate " -"variables\n" -"exist." +"The requests from machines in the lab for files contain the same basic " +"information, no matter what protocol they came from: an authentication " +"method, and a file name to retrieve. A straightforward implementation would " +"look something like this:" msgstr "" -#: src\anti_patterns/borrow_clone.md:38 +#: src/functional/generics-type-classes.md:66 msgid "" -"There are special cases -- `Rc` is designed to handle clones " -"intelligently.\n" -"It internally manages exactly one copy of the data, and cloning it will " -"only\n" -"clone the reference." +"This design might work well enough. But now suppose you needed to support " +"adding metadata that was _protocol specific_. For example, with NFS, you " +"wanted to determine what their mount point was in order to enforce " +"additional security rules." msgstr "" -#: src\anti_patterns/borrow_clone.md:42 +#: src/functional/generics-type-classes.md:71 msgid "" -"There is also `Arc` which provides shared ownership of a value of type T\n" -"that is allocated in the heap. Invoking `.clone()` on `Arc` produces a new " -"`Arc`\n" -"instance, which points to the same allocation on the heap as the source " -"`Arc`,\n" -"while increasing a reference count." +"The way the current struct is designed leaves the protocol decision until " +"runtime. That means any method that applies to one protocol and not the " +"other requires the programmer to do a runtime check." msgstr "" -#: src\anti_patterns/borrow_clone.md:47 -msgid "" -"In general, clones should be deliberate, with full understanding of the\n" -"consequences. If a clone is used to make a borrow checker error disappear,\n" -"that's a good indication this anti-pattern may be in use." +#: src/functional/generics-type-classes.md:75 +msgid "Here is how getting an NFS mount point would look:" +msgstr "" + +#: src/functional/generics-type-classes.md:85 +msgid "// ... other methods ...\n" msgstr "" -#: src\anti_patterns/borrow_clone.md:51 +#: src/functional/generics-type-classes.md:87 msgid "" -"Even though `.clone()` is an indication of a bad pattern, sometimes\n" -"**it is fine to write inefficient code**, in cases such as when:" +"/// Gets an NFS mount point if this is an NFS request. Otherwise,\n" +" /// return None.\n" msgstr "" -#: src\anti_patterns/borrow_clone.md:54 +#: src/functional/generics-type-classes.md:95 msgid "" -"- the developer is still new to ownership\n" -"- the code doesn't have great speed or memory constraints\n" -" (like hackathon projects or prototypes)\n" -"- satisfying the borrow checker is really complicated, and you prefer to\n" -" optimize readability over performance" +"Every caller of `mount_point()` must check for `None` and write code to " +"handle it. This is true even if they know only NFS requests are ever used in " +"a given code path!" msgstr "" -#: src\anti_patterns/borrow_clone.md:60 +#: src/functional/generics-type-classes.md:99 msgid "" -"If an unnecessary clone is suspected, The [Rust Book's chapter on Ownership]" -"(https://doc.rust-lang.org/book/ownership.html)\n" -"should be understood fully before assessing whether the clone is required or " -"not." +"It would be far more optimal to cause a compile-time error if the different " +"request types were confused. After all, the entire path of the user's code, " +"including what functions from the library they use, will know whether a " +"request is an NFS request or a BOOTP request." msgstr "" -#: src\anti_patterns/borrow_clone.md:63 +#: src/functional/generics-type-classes.md:104 msgid "" -"Also be sure to always run `cargo clippy` in your project, which will detect " -"some\n" -"cases in which `.clone()` is not necessary, like [1](https://rust-" -"lang.github.io/rust-clippy/master/index.html#redundant_clone),\n" -"[2](https://rust-lang.github.io/rust-clippy/master/" -"index.html#clone_on_copy),\n" -"[3](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) or " -"[4](https://rust-lang.github.io/rust-clippy/master/" -"index.html#clone_double_ref)." -msgstr "" - -#: src\anti_patterns/borrow_clone.md:70 -msgid "" -"- [`mem::{take(_), replace(_)}` to keep owned values in changed enums](../" -"idioms/mem-replace.md)\n" -"- [`Rc` documentation, which handles .clone() intelligently](http://" -"doc.rust-lang.org/std/rc/)\n" -"- [`Arc` documentation, a thread-safe reference-counting pointer](https://" -"doc.rust-lang.org/std/sync/struct.Arc.html)\n" -"- [Tricks with ownership in Rust](https://web.archive.org/web/20210120233744/" -"https://xion.io/post/code/rust-borrowchk-tricks.html)" +"In Rust, this is actually possible! The solution is to _add a generic type_ " +"in order to split the API." msgstr "" -#: src\anti_patterns/deny-warnings.md:1 -msgid "# `#![deny(warnings)]`" +#: src/functional/generics-type-classes.md:107 +msgid "Here is what that looks like:" msgstr "" -#: src\anti_patterns/deny-warnings.md:5 -msgid "" -"A well-intentioned crate author wants to ensure their code builds without\n" -"warnings. So they annotate their crate root with the following:" +#: src/functional/generics-type-classes.md:114 +msgid "// NFS session management omitted\n" +msgstr "" + +#: src/functional/generics-type-classes.md:118 +msgid "// no authentication in bootp\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:10 +#: src/functional/generics-type-classes.md:120 msgid "" -"```rust\n" -"#![deny(warnings)]\n" -"\n" -"// All is well.\n" -"```" +"// private module, lest outside users invent their own protocol kinds!\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:18 -msgid "It is short and will stop the build if anything is amiss." +#: src/functional/generics-type-classes.md:149 +msgid "// no additional metadata\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:20 -msgid "## Drawbacks" +#: src/functional/generics-type-classes.md:159 +msgid "// keep internal to prevent impls\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:22 -msgid "" -"By disallowing the compiler to build with warnings, a crate author opts out " -"of\n" -"Rust's famed stability. Sometimes new features or old misfeatures need a " -"change\n" -"in how things are done, thus lints are written that `warn` for a certain " -"grace\n" -"period before being turned to `deny`." +#: src/functional/generics-type-classes.md:160 +msgid "// re-export so callers can see them\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:27 -msgid "" -"For example, it was discovered that a type could have two `impl`s with the " -"same\n" -"method. This was deemed a bad idea, but in order to make the transition " -"smooth,\n" -"the `overlapping-inherent-impls` lint was introduced to give a warning to " -"those\n" -"stumbling on this fact, before it becomes a hard error in a future release." +#: src/functional/generics-type-classes.md:166 +msgid "// all common API parts go into a generic impl block\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:32 -msgid "" -"Also sometimes APIs get deprecated, so their use will emit a warning where\n" -"before there was none." +#: src/functional/generics-type-classes.md:177 +msgid "// all protocol-specific impls go into their own block\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:35 -msgid "" -"All this conspires to potentially break the build whenever something changes." +#: src/functional/generics-type-classes.md:186 +msgid "// your code here\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:37 +#: src/functional/generics-type-classes.md:190 msgid "" -"Furthermore, crates that supply additional lints (e.g. [rust-clippy]) can " -"no\n" -"longer be used unless the annotation is removed. This is mitigated with\n" -"[--cap-lints]. The `--cap-lints=warn` command line argument, turns all " -"`deny`\n" -"lint errors into warnings." +"With this approach, if the user were to make a mistake and use the wrong " +"type;" msgstr "" -#: src\anti_patterns/deny-warnings.md:42 -#: src\functional/generics-type-classes.md:227 -msgid "## Alternatives" +#: src/functional/generics-type-classes.md:197 +msgid "\"/secure\"" msgstr "" -#: src\anti_patterns/deny-warnings.md:44 -msgid "" -"There are two ways of tackling this problem: First, we can decouple the " -"build\n" -"setting from the code, and second, we can name the lints we want to deny\n" -"explicitly." +#: src/functional/generics-type-classes.md:197 +msgid "\"Access denied\"" msgstr "" -#: src\anti_patterns/deny-warnings.md:48 -msgid "The following command line will build with all warnings set to `deny`:" +#: src/functional/generics-type-classes.md:198 +msgid "// continue on...\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:50 -msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" +#: src/functional/generics-type-classes.md:200 +msgid "// Rest of the code here\n" msgstr "" -#: src\anti_patterns/deny-warnings.md:52 +#: src/functional/generics-type-classes.md:205 msgid "" -"This can be done by any individual developer (or be set in a CI tool like\n" -"Travis, but remember that this may break the build when something changes)\n" -"without requiring a change to the code." +"They would get a syntax error. The type `FileDownloadRequest` does " +"not implement `mount_point()`, only the type `FileDownloadRequest` " +"does. And that is created by the NFS module, not the BOOTP module of course!" msgstr "" -#: src\anti_patterns/deny-warnings.md:56 +#: src/functional/generics-type-classes.md:211 msgid "" -"Alternatively, we can specify the lints that we want to `deny` in the code.\n" -"Here is a list of warning lints that is (hopefully) safe to deny (as of " -"Rustc 1.48.0):" -msgstr "" - -#: src\anti_patterns/deny-warnings.md:59 -msgid "" -"```rust,ignore\n" -"#![deny(bad_style,\n" -" const_err,\n" -" dead_code,\n" -" improper_ctypes,\n" -" non_shorthand_field_patterns,\n" -" no_mangle_generic_items,\n" -" overflowing_literals,\n" -" path_statements,\n" -" patterns_in_fns_without_body,\n" -" private_in_public,\n" -" unconditional_recursion,\n" -" unused,\n" -" unused_allocation,\n" -" unused_comparisons,\n" -" unused_parens,\n" -" while_true)]\n" -"```" +"First, it allows fields that are common to multiple states to be de-" +"duplicated. By making the non-shared fields generic, they are implemented " +"once." msgstr "" -#: src\anti_patterns/deny-warnings.md:78 +#: src/functional/generics-type-classes.md:214 msgid "" -"In addition, the following `allow`ed lints may be a good idea to `deny`:" +"Second, it makes the `impl` blocks easier to read, because they are broken " +"down by state. Methods common to all states are typed once in one block, and " +"methods unique to one state are in a separate block." msgstr "" -#: src\anti_patterns/deny-warnings.md:80 +#: src/functional/generics-type-classes.md:218 msgid "" -"```rust,ignore\n" -"#![deny(missing_debug_implementations,\n" -" missing_docs,\n" -" trivial_casts,\n" -" trivial_numeric_casts,\n" -" unused_extern_crates,\n" -" unused_import_braces,\n" -" unused_qualifications,\n" -" unused_results)]\n" -"```" +"Both of these mean there are fewer lines of code, and they are better " +"organized." msgstr "" -#: src\anti_patterns/deny-warnings.md:91 -msgid "Some may also want to add `missing-copy-implementations` to their list." +#: src/functional/generics-type-classes.md:222 +msgid "" +"This currently increases the size of the binary, due to the way " +"monomorphization is implemented in the compiler. Hopefully the " +"implementation will be able to improve in the future." msgstr "" -#: src\anti_patterns/deny-warnings.md:93 +#: src/functional/generics-type-classes.md:228 msgid "" -"Note that we explicitly did not add the `deprecated` lint, as it is fairly\n" -"certain that there will be more deprecated APIs in the future." +"If a type seems to need a \"split API\" due to construction or partial " +"initialization, consider the [Builder Pattern](../patterns/creational/" +"builder.md) instead." msgstr "" -#: src\anti_patterns/deny-warnings.md:98 +#: src/functional/generics-type-classes.md:232 msgid "" -"- [A collection of all clippy lints](https://rust-lang.github.io/rust-clippy/" -"master)\n" -"- [deprecate attribute] documentation\n" -"- Type `rustc -W help` for a list of lints on your system. Also type\n" -" `rustc --help` for a general list of options\n" -"- [rust-clippy] is a collection of lints for better Rust code" +"If the API between types does not change -- only the behavior does -- then " +"the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used " +"instead." msgstr "" -#: src\anti_patterns/deref.md:1 -msgid "# `Deref` polymorphism" +#: src/functional/generics-type-classes.md:238 +msgid "This pattern is used throughout the standard library:" msgstr "" -#: src\anti_patterns/deref.md:5 +#: src/functional/generics-type-classes.md:240 msgid "" -"Misuse the `Deref` trait to emulate inheritance between structs, and thus " -"reuse\n" -"methods." +"`Vec` can be cast from a String, unlike every other type of `Vec`.[^1]" msgstr "" -#: src\anti_patterns/deref.md:10 +#: src/functional/generics-type-classes.md:241 msgid "" -"Sometimes we want to emulate the following common pattern from OO languages " -"such\n" -"as Java:" +"Iterators can be cast into a binary heap, but only if they contain a type " +"that implements the `Ord` trait.[^2]" msgstr "" -#: src\anti_patterns/deref.md:13 +#: src/functional/generics-type-classes.md:243 msgid "" -"```java\n" -"class Foo {\n" -" void m() { ... }\n" -"}\n" -"\n" -"class Bar extends Foo {}\n" -"\n" -"public static void main(String[] args) {\n" -" Bar b = new Bar();\n" -" b.m();\n" -"}\n" -"```" +"The `to_string` method was specialized for `Cow` only of type `str`.[^3]" msgstr "" -#: src\anti_patterns/deref.md:26 -msgid "We can use the deref polymorphism anti-pattern to do so:" +#: src/functional/generics-type-classes.md:245 +msgid "It is also used by several popular crates to allow API flexibility:" msgstr "" -#: src\anti_patterns/deref.md:28 +#: src/functional/generics-type-classes.md:247 msgid "" -"```rust\n" -"use std::ops::Deref;\n" -"\n" -"struct Foo {}\n" -"\n" -"impl Foo {\n" -" fn m(&self) {\n" -" //..\n" -" }\n" -"}\n" -"\n" -"struct Bar {\n" -" f: Foo,\n" -"}\n" -"\n" -"impl Deref for Bar {\n" -" type Target = Foo;\n" -" fn deref(&self) -> &Foo {\n" -" &self.f\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let b = Bar { f: Foo {} };\n" -" b.m();\n" -"}\n" -"```" +"The `embedded-hal` ecosystem used for embedded devices makes extensive use " +"of this pattern. For example, it allows statically verifying the " +"configuration of device registers used to control embedded pins. When a pin " +"is put into a mode, it returns a `Pin` struct, whose generic " +"determines the functions usable in that mode, which are not on the `Pin` " +"itself. [^4]" msgstr "" -#: src\anti_patterns/deref.md:56 +#: src/functional/generics-type-classes.md:253 msgid "" -"There is no struct inheritance in Rust. Instead we use composition and " -"include\n" -"an instance of `Foo` in `Bar` (since the field is a value, it is stored " -"inline,\n" -"so if there were fields, they would have the same layout in memory as the " -"Java\n" -"version (probably, you should use `#[repr(C)]` if you want to be sure))." +"The `hyper` HTTP client library uses this to expose rich APIs for different " +"pluggable requests. Clients with different connectors have different methods " +"on them as well as different trait implementations, while a core set of " +"methods apply to any connector. [^5]" msgstr "" -#: src\anti_patterns/deref.md:61 +#: src/functional/generics-type-classes.md:258 msgid "" -"In order to make the method call work we implement `Deref` for `Bar` with " -"`Foo`\n" -"as the target (returning the embedded `Foo` field). That means that when we\n" -"dereference a `Bar` (for example, using `*`) then we will get a `Foo`. That " -"is\n" -"pretty weird. Dereferencing usually gives a `T` from a reference to `T`, " -"here we\n" -"have two unrelated types. However, since the dot operator does implicit\n" -"dereferencing, it means that the method call will search for methods on " -"`Foo` as\n" -"well as `Bar`." -msgstr "" - -#: src\anti_patterns/deref.md:71 -msgid "You save a little boilerplate, e.g.," +"The \"type state\" pattern -- where an object gains and loses API based on " +"an internal state or invariant -- is implemented in Rust using the same " +"basic concept, and a slightly different technique. [^6]" msgstr "" -#: src\anti_patterns/deref.md:73 +#: src/functional/generics-type-classes.md:262 msgid "" -"```rust,ignore\n" -"impl Bar {\n" -" fn m(&self) {\n" -" self.f.m()\n" -" }\n" -"}\n" -"```" +"See: [impl From\\ for Vec\\](https://doc.rust-lang.org/" +"1.59.0/src/std/ffi/c_str.rs.html#803-811)" msgstr "" -#: src\anti_patterns/deref.md:83 +#: src/functional/generics-type-classes.md:265 msgid "" -"Most importantly this is a surprising idiom - future programmers reading " -"this in\n" -"code will not expect this to happen. That's because we are misusing the " -"`Deref`\n" -"trait rather than using it as intended (and documented, etc.). It's also " -"because\n" -"the mechanism here is completely implicit." +"See: [impl\\ FromIterator\\ for BinaryHeap\\](https://" +"web.archive.org/web/20201030132806/https://doc.rust-lang.org/stable/src/" +"alloc/collections/binary_heap.rs.html#1330-1335)" msgstr "" -#: src\anti_patterns/deref.md:88 +#: src/functional/generics-type-classes.md:268 msgid "" -"This pattern does not introduce subtyping between `Foo` and `Bar` like\n" -"inheritance in Java or C++ does. Furthermore, traits implemented by `Foo` " -"are\n" -"not automatically implemented for `Bar`, so this pattern interacts badly " -"with\n" -"bounds checking and thus generic programming." +"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, str>](https://doc.rust-" +"lang.org/stable/src/alloc/string.rs.html#2235-2240)" msgstr "" -#: src\anti_patterns/deref.md:93 +#: src/functional/generics-type-classes.md:271 msgid "" -"Using this pattern gives subtly different semantics from most OO languages " -"with\n" -"regards to `self`. Usually it remains a reference to the sub-class, with " -"this\n" -"pattern it will be the 'class' where the method is defined." +"Example: [https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/gpioa/" +"struct.PA0.html](https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/" +"gpioa/struct.PA0.html)" msgstr "" -#: src\anti_patterns/deref.md:97 +#: src/functional/generics-type-classes.md:274 msgid "" -"Finally, this pattern only supports single inheritance, and has no notion " -"of\n" -"interfaces, class-based privacy, or other inheritance-related features. So, " -"it\n" -"gives an experience that will be subtly surprising to programmers used to " -"Java\n" -"inheritance, etc." +"See: [https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html](https://" +"docs.rs/hyper/0.14.5/hyper/client/struct.Client.html)" msgstr "" -#: src\anti_patterns/deref.md:104 +#: src/functional/generics-type-classes.md:277 msgid "" -"There is no one good alternative. Depending on the exact circumstances it " -"might\n" -"be better to re-implement using traits or to write out the facade methods " -"to\n" -"dispatch to `Foo` manually. We do intend to add a mechanism for inheritance\n" -"similar to this to Rust, but it is likely to be some time before it reaches\n" -"stable Rust. See these [blog](http://aturon.github.io/blog/2015/09/18/" -"reuse/)\n" -"[posts](http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-" -"structs-part-4-extended-enums-and-thin-traits/)\n" -"and this [RFC issue](https://github.com/rust-lang/rfcs/issues/349) for more " -"details." +"See: [The Case for the Type State Pattern](https://web.archive.org/web/" +"20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-" +"typestate-pattern-the-typestate-pattern-itself/) and [Rusty Typestate Series " +"(an extensive thesis)](https://web.archive.org/web/20210328164854/https://" +"rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index)" msgstr "" -#: src\anti_patterns/deref.md:112 +#: src/functional/optics.md:1 +msgid "Functional Language Optics" +msgstr "" + +#: src/functional/optics.md:3 msgid "" -"The `Deref` trait is designed for the implementation of custom pointer " -"types.\n" -"The intention is that it will take a pointer-to-`T` to a `T`, not convert\n" -"between different types. It is a shame that this isn't (probably cannot be)\n" -"enforced by the trait definition." +"Optics is a type of API design that is common to functional languages. This " +"is a pure functional concept that is not frequently used in Rust." msgstr "" -#: src\anti_patterns/deref.md:117 +#: src/functional/optics.md:6 msgid "" -"Rust tries to strike a careful balance between explicit and implicit " -"mechanisms,\n" -"favouring explicit conversions between types. Automatic dereferencing in the " -"dot\n" -"operator is a case where the ergonomics strongly favour an implicit " -"mechanism,\n" -"but the intention is that this is limited to degrees of indirection, not\n" -"conversion between arbitrary types." -msgstr "" - -#: src\anti_patterns/deref.md:125 -msgid "" -"- [Collections are smart pointers idiom](../idioms/deref.md).\n" -"- Delegation crates for less boilerplate like [delegate](https://crates.io/" -"crates/delegate)\n" -" or [ambassador](https://crates.io/crates/ambassador)\n" -"- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" -"trait.Deref.html)." +"Nevertheless, exploring the concept may be helpful to understand other " +"patterns in Rust APIs, such as [visitors](../patterns/behavioural/" +"visitor.md). They also have niche use cases." msgstr "" -#: src\functional/index.md:1 -msgid "# Functional Usage of Rust" +#: src/functional/optics.md:10 +msgid "" +"This is quite a large topic, and would require actual books on language " +"design to fully get into its abilities. However their applicability in Rust " +"is much simpler." msgstr "" -#: src\functional/index.md:3 +#: src/functional/optics.md:14 msgid "" -"Rust is an imperative language, but it follows many\n" -"[functional programming](https://en.wikipedia.org/wiki/" -"Functional_programming) paradigms." +"To explain the relevant parts of the concept, the `Serde`\\-API will be used " +"as an example, as it is one that is difficult for many to understand from " +"simply the API documentation." msgstr "" -#: src\functional/index.md:6 +#: src/functional/optics.md:18 msgid "" -"> In computer science, _functional programming_ is a programming paradigm " -"where\n" -"> programs are constructed by applying and composing functions.\n" -"> It is a declarative programming paradigm in which function definitions " -"are\n" -"> trees of expressions that each return a value, rather than a sequence of\n" -"> imperative statements which change the state of the program." +"In the process, different specific patterns, called Optics, will be covered. " +"These are _The Iso_, _The Poly Iso_, and _The Prism_." msgstr "" -#: src\functional/paradigms.md:1 -msgid "# Programming paradigms" +#: src/functional/optics.md:21 +msgid "An API Example: Serde" msgstr "" -#: src\functional/paradigms.md:3 +#: src/functional/optics.md:23 msgid "" -"One of the biggest hurdles to understanding functional programs when coming\n" -"from an imperative background is the shift in thinking. Imperative programs\n" -"describe **how** to do something, whereas declarative programs describe\n" -"**what** to do. Let's sum the numbers from 1 to 10 to show this." +"Trying to understand the way _Serde_ works by only reading the API is a " +"challenge, especially the first time. Consider the `Deserializer` trait, " +"implemented by any library which parses a new data format:" msgstr "" -#: src\functional/paradigms.md:8 -msgid "## Imperative" +#: src/functional/optics.md:39 src/functional/optics.md:61 +#: src/functional/optics.md:379 src/functional/optics.md:401 +msgid "// remainder omitted\n" msgstr "" -#: src\functional/paradigms.md:10 -msgid "" -"```rust\n" -"let mut sum = 0;\n" -"for i in 1..11 {\n" -" sum += i;\n" -"}\n" -"println!(\"{}\", sum);\n" -"```" +#: src/functional/optics.md:43 +msgid "And here's the definition of the `Visitor` trait passed in generically:" msgstr "" -#: src\functional/paradigms.md:18 +#: src/functional/optics.md:65 msgid "" -"With imperative programs, we have to play compiler to see what is " -"happening.\n" -"Here, we start with a `sum` of `0`.\n" -"Next, we iterate through the range from 1 to 10.\n" -"Each time through the loop, we add the corresponding value in the range.\n" -"Then we print it out." +"There is a lot of type erasure going on here, with multiple levels of " +"associated types being passed back and forth." msgstr "" -#: src\functional/paradigms.md:24 +#: src/functional/optics.md:68 msgid "" -"| `i` | `sum` |\n" -"| :-: | :---: |\n" -"| 1 | 1 |\n" -"| 2 | 3 |\n" -"| 3 | 6 |\n" -"| 4 | 10 |\n" -"| 5 | 15 |\n" -"| 6 | 21 |\n" -"| 7 | 28 |\n" -"| 8 | 36 |\n" -"| 9 | 45 |\n" -"| 10 | 55 |" +"But what is the big picture? Why not just have the `Visitor` return the " +"pieces the caller needs in a streaming API, and call it a day? Why all the " +"extra pieces?" msgstr "" -#: src\functional/paradigms.md:37 +#: src/functional/optics.md:72 msgid "" -"This is how most of us start out programming. We learn that a program is a " -"set\n" -"of steps." -msgstr "" - -#: src\functional/paradigms.md:40 -msgid "## Declarative" +"One way to understand it is to look at a functional languages concept called " +"_optics_." msgstr "" -#: src\functional/paradigms.md:42 +#: src/functional/optics.md:75 msgid "" -"```rust\n" -"println!(\"{}\", (1..11).fold(0, |a, b| a + b));\n" -"```" +"This is a way to do composition of behavior and proprieties that is designed " +"to facilitate patterns common to Rust: failure, type transformation, etc.[^1]" msgstr "" -#: src\functional/paradigms.md:46 +#: src/functional/optics.md:78 msgid "" -"Whoa! This is really different! What's going on here?\n" -"Remember that with declarative programs we are describing **what** to do,\n" -"rather than **how** to do it. `fold` is a function that [composes](https://" -"en.wikipedia.org/wiki/Function_composition)\n" -"functions. The name is a convention from Haskell." +"The Rust language does not have very good support for these directly. " +"However, they appear in the design of the language itself, and their " +"concepts can help to understand some of Rust's APIs. As a result, this " +"attempts to explain the concepts with the way Rust does it." msgstr "" -#: src\functional/paradigms.md:51 +#: src/functional/optics.md:83 msgid "" -"Here, we are composing functions of addition (this closure: `|a, b| a + b`)\n" -"with a range from 1 to 10. The `0` is the starting point, so `a` is `0` at\n" -"first. `b` is the first element of the range, `1`. `0 + 1 = 1` is the " -"result.\n" -"So now we `fold` again, with `a = 1`, `b = 2` and so `1 + 2 = 3` is the " -"next\n" -"result. This process continues until we get to the last element in the " -"range,\n" -"`10`." +"This will perhaps shed light on what those APIs are achieving: specific " +"properties of composability." msgstr "" -#: src\functional/paradigms.md:58 -msgid "" -"| `a` | `b` | result |\n" -"| :-: | :-: | :----: |\n" -"| 0 | 1 | 1 |\n" -"| 1 | 2 | 3 |\n" -"| 3 | 3 | 6 |\n" -"| 6 | 4 | 10 |\n" -"| 10 | 5 | 15 |\n" -"| 15 | 6 | 21 |\n" -"| 21 | 7 | 28 |\n" -"| 28 | 8 | 36 |\n" -"| 36 | 9 | 45 |\n" -"| 45 | 10 | 55 |" +#: src/functional/optics.md:86 +msgid "Basic Optics" msgstr "" -#: src\functional/generics-type-classes.md:1 -msgid "# Generics as Type Classes" +#: src/functional/optics.md:88 +msgid "The Iso" msgstr "" -#: src\functional/generics-type-classes.md:5 +#: src/functional/optics.md:90 msgid "" -"Rust's type system is designed more like functional languages (like " -"Haskell)\n" -"rather than imperative languages (like Java and C++). As a result, Rust can " -"turn\n" -"many kinds of programming problems into \"static typing\" problems. This is " -"one\n" -"of the biggest wins of choosing a functional language, and is critical to " -"many\n" -"of Rust's compile time guarantees." +"The Iso is a value transformer between two types. It is extremely simple, " +"but a conceptually important building block." msgstr "" -#: src\functional/generics-type-classes.md:11 +#: src/functional/optics.md:93 msgid "" -"A key part of this idea is the way generic types work. In C++ and Java, for\n" -"example, generic types are a meta-programming construct for the compiler.\n" -"`vector` and `vector` in C++ are just two different copies of " -"the\n" -"same boilerplate code for a `vector` type (known as a `template`) with two\n" -"different types filled in." +"As an example, suppose that we have a custom Hash table structure used as a " +"concordance for a document.[^2] It uses strings for keys (words) and a list " +"of indexes for values (file offsets, for instance)." msgstr "" -#: src\functional/generics-type-classes.md:17 +#: src/functional/optics.md:97 msgid "" -"In Rust, a generic type parameter creates what is known in functional " -"languages\n" -"as a \"type class constraint\", and each different parameter filled in by an " -"end\n" -"user _actually changes the type_. In other words, `Vec` and " -"`Vec`\n" -"_are two different types_, which are recognized as distinct by all parts of " -"the\n" -"type system." +"A key feature is the ability to serialize this format to disk. A \"quick and " +"dirty\" approach would be to implement a conversion to and from a string in " +"JSON format. (Errors are ignored for the time being, they will be handled " +"later.)" msgstr "" -#: src\functional/generics-type-classes.md:23 -msgid "" -"This is called **monomorphization**, where different types are created from\n" -"**polymorphic** code. This special behavior requires `impl` blocks to " -"specify\n" -"generic parameters. Different values for the generic type cause different " -"types,\n" -"and different types can have different `impl` blocks." +#: src/functional/optics.md:101 +msgid "To write it in a normal form expected by functional language users:" msgstr "" -#: src\functional/generics-type-classes.md:28 +#: src/functional/optics.md:110 msgid "" -"In object-oriented languages, classes can inherit behavior from their " -"parents.\n" -"However, this allows the attachment of not only additional behavior to\n" -"particular members of a type class, but extra behavior as well." +"The Iso is thus a pair of functions which convert values of different types: " +"`serialize` and `deserialize`." msgstr "" -#: src\functional/generics-type-classes.md:32 -msgid "" -"The nearest equivalent is the runtime polymorphism in Javascript and " -"Python,\n" -"where new members can be added to objects willy-nilly by any constructor.\n" -"However, unlike those languages, all of Rust's additional methods can be " -"type\n" -"checked when they are used, because their generics are statically defined. " -"That\n" -"makes them more usable while remaining safe." +#: src/functional/optics.md:113 +msgid "A straightforward implementation:" msgstr "" -#: src\functional/generics-type-classes.md:40 -msgid "" -"Suppose you are designing a storage server for a series of lab machines.\n" -"Because of the software involved, there are two different protocols you " -"need\n" -"to support: BOOTP (for PXE network boot), and NFS (for remote mount storage)." +#: src/functional/optics.md:129 +msgid "// invalid concordances are empty\n" msgstr "" -#: src\functional/generics-type-classes.md:44 +#: src/functional/optics.md:136 msgid "" -"Your goal is to have one program, written in Rust, which can handle both of\n" -"them. It will have protocol handlers and listen for both kinds of requests. " -"The\n" -"main application logic will then allow a lab administrator to configure " -"storage\n" -"and security controls for the actual files." +"This may seem rather silly. In Rust, this type of behavior is typically done " +"with traits. After all, the standard library has `FromStr` and `ToString` in " +"it." msgstr "" -#: src\functional/generics-type-classes.md:49 -msgid "" -"The requests from machines in the lab for files contain the same basic\n" -"information, no matter what protocol they came from: an authentication " -"method,\n" -"and a file name to retrieve. A straightforward implementation would look\n" -"something like this:" +#: src/functional/optics.md:139 +msgid "But that is where our next subject comes in: Poly Isos." +msgstr "" + +#: src/functional/optics.md:141 +msgid "Poly Isos" msgstr "" -#: src\functional/generics-type-classes.md:54 +#: src/functional/optics.md:143 msgid "" -"```rust,ignore\n" -"enum AuthInfo {\n" -" Nfs(crate::nfs::AuthInfo),\n" -" Bootp(crate::bootp::AuthInfo),\n" -"}\n" -"\n" -"struct FileDownloadRequest {\n" -" file_name: PathBuf,\n" -" authentication: AuthInfo,\n" -"}\n" -"```" +"The previous example was simply converting between values of two fixed " +"types. This next block builds upon it with generics, and is more interesting." msgstr "" -#: src\functional/generics-type-classes.md:66 +#: src/functional/optics.md:146 msgid "" -"This design might work well enough. But now suppose you needed to support\n" -"adding metadata that was _protocol specific_. For example, with NFS, you\n" -"wanted to determine what their mount point was in order to enforce " -"additional\n" -"security rules." +"Poly Isos allow an operation to be generic over any type while returning a " +"single type." msgstr "" -#: src\functional/generics-type-classes.md:71 +#: src/functional/optics.md:149 msgid "" -"The way the current struct is designed leaves the protocol decision until\n" -"runtime. That means any method that applies to one protocol and not the " -"other\n" -"requires the programmer to do a runtime check." +"This brings us closer to parsing. Consider what a basic parser would do " +"ignoring error cases. Again, this is its normal form:" msgstr "" -#: src\functional/generics-type-classes.md:75 -msgid "Here is how getting an NFS mount point would look:" +#: src/functional/optics.md:159 +msgid "Here we have our first generic, the type `T` being converted." msgstr "" -#: src\functional/generics-type-classes.md:77 +#: src/functional/optics.md:161 msgid "" -"```rust,ignore\n" -"struct FileDownloadRequest {\n" -" file_name: PathBuf,\n" -" authentication: AuthInfo,\n" -" mount_point: Option,\n" -"}\n" -"\n" -"impl FileDownloadRequest {\n" -" // ... other methods ...\n" -"\n" -" /// Gets an NFS mount point if this is an NFS request. Otherwise,\n" -" /// return None.\n" -" pub fn mount_point(&self) -> Option<&Path> {\n" -" self.mount_point.as_ref()\n" -" }\n" -"}\n" -"```" +"In Rust, this could be implemented with a pair of traits in the standard " +"library: `FromStr` and `ToString`. The Rust version even handles errors:" msgstr "" -#: src\functional/generics-type-classes.md:95 +#: src/functional/optics.md:176 msgid "" -"Every caller of `mount_point()` must check for `None` and write code to " -"handle\n" -"it. This is true even if they know only NFS requests are ever used in a " -"given\n" -"code path!" +"Unlike the Iso, the Poly Iso allows application of multiple types, and " +"returns them generically. This is what you would want for a basic string " +"parser." msgstr "" -#: src\functional/generics-type-classes.md:99 +#: src/functional/optics.md:179 msgid "" -"It would be far more optimal to cause a compile-time error if the different\n" -"request types were confused. After all, the entire path of the user's code,\n" -"including what functions from the library they use, will know whether a " -"request\n" -"is an NFS request or a BOOTP request." +"At first glance, this seems like a good option for writing a parser. Let's " +"see it in action:" msgstr "" -#: src\functional/generics-type-classes.md:104 -msgid "" -"In Rust, this is actually possible! The solution is to _add a generic type_ " -"in\n" -"order to split the API." +#: src/functional/optics.md:208 src/functional/optics.md:282 +msgid "\"hello\"" msgstr "" -#: src\functional/generics-type-classes.md:107 -msgid "Here is what that looks like:" +#: src/functional/optics.md:210 +msgid "\"Our Test Struct as JSON: {}\"" msgstr "" -#: src\functional/generics-type-classes.md:109 -msgid "" -"```rust\n" -"use std::path::{Path, PathBuf};\n" -"\n" -"mod nfs {\n" -" #[derive(Clone)]\n" -" pub(crate) struct AuthInfo(String); // NFS session management omitted\n" -"}\n" -"\n" -"mod bootp {\n" -" pub(crate) struct AuthInfo(); // no authentication in bootp\n" -"}\n" -"\n" -"// private module, lest outside users invent their own protocol kinds!\n" -"mod proto_trait {\n" -" use std::path::{Path, PathBuf};\n" -" use super::{bootp, nfs};\n" -"\n" -" pub(crate) trait ProtoKind {\n" -" type AuthInfo;\n" -" fn auth_info(&self) -> Self::AuthInfo;\n" -" }\n" -"\n" -" pub struct Nfs {\n" -" auth: nfs::AuthInfo,\n" -" mount_point: PathBuf,\n" -" }\n" -"\n" -" impl Nfs {\n" -" pub(crate) fn mount_point(&self) -> &Path {\n" -" &self.mount_point\n" -" }\n" -" }\n" -"\n" -" impl ProtoKind for Nfs {\n" -" type AuthInfo = nfs::AuthInfo;\n" -" fn auth_info(&self) -> Self::AuthInfo {\n" -" self.auth.clone()\n" -" }\n" -" }\n" -"\n" -" pub struct Bootp(); // no additional metadata\n" -"\n" -" impl ProtoKind for Bootp {\n" -" type AuthInfo = bootp::AuthInfo;\n" -" fn auth_info(&self) -> Self::AuthInfo {\n" -" bootp::AuthInfo()\n" -" }\n" -" }\n" -"}\n" -"\n" -"use proto_trait::ProtoKind; // keep internal to prevent impls\n" -"pub use proto_trait::{Nfs, Bootp}; // re-export so callers can see them\n" -"\n" -"struct FileDownloadRequest {\n" -" file_name: PathBuf,\n" -" protocol: P,\n" -"}\n" -"\n" -"// all common API parts go into a generic impl block\n" -"impl FileDownloadRequest

{\n" -" fn file_path(&self) -> &Path {\n" -" &self.file_name\n" -" }\n" -"\n" -" fn auth_info(&self) -> P::AuthInfo {\n" -" self.protocol.auth_info()\n" -" }\n" -"}\n" -"\n" -"// all protocol-specific impls go into their own block\n" -"impl FileDownloadRequest {\n" -" fn mount_point(&self) -> &Path {\n" -" self.protocol.mount_point()\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" // your code here\n" -"}\n" -"```" +#: src/functional/optics.md:214 +msgid "That seems quite logical. However, there are two problems with this." msgstr "" -#: src\functional/generics-type-classes.md:190 +#: src/functional/optics.md:216 msgid "" -"With this approach, if the user were to make a mistake and use the wrong\n" -"type;" +"First, `to_string` does not indicate to API users, \"this is JSON.\" Every " +"type would need to agree on a JSON representation, and many of the types in " +"the Rust standard library already don't. Using this is a poor fit. This can " +"easily be resolved with our own trait." msgstr "" -#: src\functional/generics-type-classes.md:193 -msgid "" -"```rust,ignore\n" -"fn main() {\n" -" let mut socket = crate::bootp::listen()?;\n" -" while let Some(request) = socket.next_request()? {\n" -" match request.mount_point().as_ref()\n" -" \"/secure\" => socket.send(\"Access denied\"),\n" -" _ => {} // continue on...\n" -" }\n" -" // Rest of the code here\n" -" }\n" -"}\n" -"```" +#: src/functional/optics.md:221 +msgid "But there is a second, subtler problem: scaling." msgstr "" -#: src\functional/generics-type-classes.md:206 +#: src/functional/optics.md:223 msgid "" -"They would get a syntax error. The type `FileDownloadRequest` does " -"not\n" -"implement `mount_point()`, only the type `FileDownloadRequest` does. " -"And\n" -"that is created by the NFS module, not the BOOTP module of course!" +"When every type writes `to_string` by hand, this works. But if every single " +"person who wants their type to be serializable has to write a bunch of code " +"-- and possibly different JSON libraries -- to do it themselves, it will " +"turn into a mess very quickly!" msgstr "" -#: src\functional/generics-type-classes.md:212 +#: src/functional/optics.md:228 msgid "" -"First, it allows fields that are common to multiple states to be de-" -"duplicated.\n" -"By making the non-shared fields generic, they are implemented once." +"The answer is one of Serde's two key innovations: an independent data model " +"to represent Rust data in structures common to data serialization languages. " +"The result is that it can use Rust's code generation abilities to create an " +"intermediary conversion type it calls a `Visitor`." msgstr "" -#: src\functional/generics-type-classes.md:215 +#: src/functional/optics.md:233 msgid "" -"Second, it makes the `impl` blocks easier to read, because they are broken " -"down\n" -"by state. Methods common to all states are typed once in one block, and " -"methods\n" -"unique to one state are in a separate block." +"This means, in normal form (again, skipping error handling for simplicity):" msgstr "" -#: src\functional/generics-type-classes.md:219 +#: src/functional/optics.md:247 msgid "" -"Both of these mean there are fewer lines of code, and they are better " -"organized." +"The result is one Poly Iso and one Iso (respectively). Both of these can be " +"implemented with traits:" msgstr "" -#: src\functional/generics-type-classes.md:223 +#: src/functional/optics.md:263 msgid "" -"This currently increases the size of the binary, due to the way " -"monomorphization\n" -"is implemented in the compiler. Hopefully the implementation will be able " -"to\n" -"improve in the future." +"Because there is a uniform set of rules to transform Rust structures to the " +"independent form, it is even possible to have code generation creating the " +"`Visitor` associated with type `T`:" msgstr "" -#: src\functional/generics-type-classes.md:229 -msgid "" -"- If a type seems to need a \"split API\" due to construction or partial\n" -" initialization, consider the\n" -" [Builder Pattern](../patterns/creational/builder.md) instead.\n" -"\n" -"- If the API between types does not change -- only the behavior does -- " -"then\n" -" the [Strategy Pattern](../patterns/behavioural/strategy.md) is better " -"used\n" -" instead." +#: src/functional/optics.md:268 +msgid "// the \"Serde\" derive creates the trait impl block\n" msgstr "" -#: src\functional/generics-type-classes.md:239 -msgid "This pattern is used throughout the standard library:" +#: src/functional/optics.md:273 +msgid "// user writes this macro to generate an associated visitor type\n" msgstr "" -#: src\functional/generics-type-classes.md:241 -msgid "" -"- `Vec` can be cast from a String, unlike every other type of `Vec`." -"[^1]\n" -"- They can also be cast into a binary heap, but only if they contain a type\n" -" that implements the `Ord` trait.[^2]\n" -"- The `to_string` method was specialized for `Cow` only of type `str`.[^3]" +#: src/functional/optics.md:278 +msgid "But let's actually try that approach." msgstr "" -#: src\functional/generics-type-classes.md:246 -msgid "It is also used by several popular crates to allow API flexibility:" +#: src/functional/optics.md:284 +msgid "\"Our Test Struct as JSON: {a_data}\"" msgstr "" -#: src\functional/generics-type-classes.md:248 +#: src/functional/optics.md:290 msgid "" -"- The `embedded-hal` ecosystem used for embedded devices makes extensive use " -"of\n" -" this pattern. For example, it allows statically verifying the " -"configuration of\n" -" device registers used to control embedded pins. When a pin is put into a " -"mode,\n" -" it returns a `Pin` struct, whose generic determines the functions\n" -" usable in that mode, which are not on the `Pin` itself. [^4]\n" -"\n" -"- The `hyper` HTTP client library uses this to expose rich APIs for " -"different\n" -" pluggable requests. Clients with different connectors have different " -"methods\n" -" on them as well as different trait implementations, while a core set of\n" -" methods apply to any connector. [^5]\n" -"\n" -"- The \"type state\" pattern -- where an object gains and loses API based on " -"an\n" -" internal state or invariant -- is implemented in Rust using the same " -"basic\n" -" concept, and a slightly different technique. [^6]" +"It turns out that the conversion isn't symmetric after all! On paper it is, " +"but with the auto-generated code the name of the actual type necessary to " +"convert all the way from `String` is hidden. We'd need some kind of " +"`generated_visitor_for!` macro to obtain the type name." msgstr "" -#: src\functional/generics-type-classes.md:263 -msgid "" -"See: [impl From\\ for Vec\\](https://doc.rust-lang.org/" -"1.59.0/src/std/ffi/c_str.rs.html#803-811)" +#: src/functional/optics.md:295 +msgid "It's wonky, but it works... until we get to the elephant in the room." msgstr "" -#: src\functional/generics-type-classes.md:265 +#: src/functional/optics.md:297 msgid "" -"See: [impl\\ From\\\\> for BinaryHeap\\]" -"(https://doc.rust-lang.org/stable/src/alloc/collections/" -"binary_heap.rs.html#1345-1354)" +"The only format currently supported is JSON. How would we support more " +"formats?" msgstr "" -#: src\functional/generics-type-classes.md:267 +#: src/functional/optics.md:299 msgid "" -"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, str>](https://doc.rust-" -"lang.org/stable/src/alloc/string.rs.html#2235-2240)" +"The current design requires completely re-writing all of the code generation " +"and creating a new Serde trait. That is quite terrible and not extensible at " +"all!" msgstr "" -#: src\functional/generics-type-classes.md:269 -msgid "" -"Example:\n" -"[https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/gpioa/" -"struct.PA0.html](https://docs.rs/stm32f30x-hal/0.1.0/stm32f30x_hal/gpio/" -"gpioa/struct.PA0.html)" +#: src/functional/optics.md:302 +msgid "In order to solve that, we need something more powerful." msgstr "" -#: src\functional/generics-type-classes.md:272 -msgid "" -"See:\n" -"[https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html](https://" -"docs.rs/hyper/0.14.5/hyper/client/struct.Client.html)" +#: src/functional/optics.md:304 +msgid "Prism" msgstr "" -#: src\functional/generics-type-classes.md:275 +#: src/functional/optics.md:306 msgid "" -"See:\n" -"[The Case for the Type State Pattern](https://web.archive.org/web/" -"20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-" -"typestate-pattern-the-typestate-pattern-itself/)\n" -"and\n" -"[Rusty Typestate Series (an extensive thesis)](https://web.archive.org/web/" -"20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/" -"rust-typestate-index)" +"To take format into account, we need something in normal form like this:" msgstr "" -#: src\functional/lenses.md:1 -msgid "# Lenses and Prisms" +#: src/functional/optics.md:315 +msgid "" +"This construct is called a Prism. It is \"one level higher\" in generics " +"than Poly Isos (in this case, the \"intersecting\" type F is the key)." msgstr "" -#: src\functional/lenses.md:3 +#: src/functional/optics.md:318 msgid "" -"This is a pure functional concept that is not frequently used in Rust.\n" -"Nevertheless, exploring the concept may be helpful to understand other\n" -"patterns in Rust APIs, such as [visitors](../patterns/behavioural/" -"visitor.md).\n" -"They also have niche use cases." +"Unfortunately because `Visitor` is a trait (since each incarnation requires " +"its own custom code), this would require a kind of generic type boundary " +"that Rust does not support." msgstr "" -#: src\functional/lenses.md:8 -msgid "## Lenses: Uniform Access Across Types" +#: src/functional/optics.md:322 +msgid "" +"Fortunately, we still have that `Visitor` type from before. What is the " +"`Visitor` doing? It is attempting to allow each data structure to define the " +"way it is itself parsed." msgstr "" -#: src\functional/lenses.md:10 +#: src/functional/optics.md:326 msgid "" -"A lens is a concept from functional programming languages that allows\n" -"accessing parts of a data type in an abstract, unified way.[^1]\n" -"In basic concept, it is similar to the way Rust traits work with type " -"erasure,\n" -"but it has a bit more power and flexibility." +"Well what if we could add one more interface for the generic format? Then " +"the `Visitor` is just an implementation detail, and it would \"bridge\" the " +"two APIs." msgstr "" -#: src\functional/lenses.md:15 -msgid "" -"For example, suppose a bank contains several JSON formats for customer\n" -"data.\n" -"This is because they come from different databases or legacy systems.\n" -"One database contains the data needed to perform credit checks:" +#: src/functional/optics.md:329 +msgid "In normal form:" msgstr "" -#: src\functional/lenses.md:20 +#: src/functional/optics.md:348 msgid "" -"```json\n" -"{ \"name\": \"Jane Doe\",\n" -" \"dob\": \"2002-02-24\",\n" -" [...]\n" -" \"customer_id\": 1048576332,\n" -"}\n" -"```" +"And what do you know, a pair of Poly Isos at the bottom which can be " +"implemented as traits!" msgstr "" -#: src\functional/lenses.md:28 -msgid "Another one contains the account information:" +#: src/functional/optics.md:351 +msgid "Thus we have the Serde API:" msgstr "" -#: src\functional/lenses.md:30 +#: src/functional/optics.md:353 msgid "" -"```json\n" -"{ \"customer_id\": 1048576332,\n" -" \"accounts\": [\n" -" { \"account_id\": 2121,\n" -" \"account_type: \"savings\",\n" -" \"joint_customer_ids\": [],\n" -" [...]\n" -" },\n" -" { \"account_id\": 2122,\n" -" \"account_type: \"checking\",\n" -" \"joint_customer_ids\": [1048576333],\n" -" [...]\n" -" },\n" -" ]\n" -"}\n" -"```" +"Each type to be serialized implements `Deserialize` or `Serialize`, " +"equivalent to the `Serde` class" msgstr "" -#: src\functional/lenses.md:47 +#: src/functional/optics.md:355 msgid "" -"Notice that both types have a customer ID number which corresponds to a " -"person.\n" -"How would a single function handle both records of different types?" +"They get a type (well two, one for each direction) implementing the " +"`Visitor` trait, which is usually (but not always) done through code " +"generated by a derive macro. This contains the logic to construct or " +"destruct between the data type and the format of the Serde data model." msgstr "" -#: src\functional/lenses.md:50 +#: src/functional/optics.md:359 msgid "" -"In Rust, a `struct` could represent each of these types, and a trait would " -"have\n" -"a `get_customer_id` function they would implement:" +"The type implementing the `Deserializer` trait handles all details specific " +"to the format, being \"driven by\" the `Visitor`." msgstr "" -#: src\functional/lenses.md:53 +#: src/functional/optics.md:362 msgid "" -"```rust\n" -"use std::collections::HashSet;\n" -"\n" -"pub struct Account {\n" -" account_id: u32,\n" -" account_type: String,\n" -" // other fields omitted\n" -"}\n" -"\n" -"pub trait CustomerId {\n" -" fn get_customer_id(&self) -> u64;\n" -"}\n" -"\n" -"pub struct CreditRecord {\n" -" customer_id: u64,\n" -" name: String,\n" -" dob: String,\n" -" // other fields omitted\n" -"}\n" -"\n" -"impl CustomerId for CreditRecord {\n" -" fn get_customer_id(&self) -> u64 {\n" -" self.customer_id\n" -" }\n" -"}\n" -"\n" -"pub struct AccountRecord {\n" -" customer_id: u64,\n" -" accounts: Vec,\n" -"}\n" -"\n" -"impl CustomerId for AccountRecord {\n" -" fn get_customer_id(&self) -> u64 {\n" -" self.customer_id\n" -" }\n" -"}\n" -"\n" -"// static polymorphism: only one type, but each function call can choose it\n" -"fn unique_ids_set(records: &[R]) -> HashSet {\n" -" records.iter().map(|r| r.get_customer_id()).collect()\n" -"}\n" -"\n" -"// dynamic dispatch: iterates over any type with a customer ID, collecting " -"all\n" -"// values together\n" -"fn unique_ids_iter(iterator: I) -> HashSet\n" -" where I: Iterator>\n" -"{\n" -" iterator.map(|r| r.as_ref().get_customer_id()).collect()\n" -"}\n" -"```" +"This splitting and Rust type erasure is really to achieve a Prism through " +"indirection." msgstr "" -#: src\functional/lenses.md:104 -msgid "" -"Lenses, however, allow the code supporting customer ID to be moved from the\n" -"_type_ to the _accessor function_.\n" -"Rather than implementing a trait on each type, all matching structures can\n" -"simply be accessed the same way." +#: src/functional/optics.md:365 +msgid "You can see it on the `Deserializer` trait" msgstr "" -#: src\functional/lenses.md:109 -msgid "" -"While the Rust language itself does not support this (type erasure is the\n" -"preferred solution to this problem), the [lens-rs crate](https://github.com/" -"TOETOE55/lens-rs/blob/master/guide.md) allows code\n" -"that feels like this to be written with macros:" +#: src/functional/optics.md:383 +msgid "And the visitor:" msgstr "" -#: src\functional/lenses.md:113 -msgid "" -"```rust,ignore\n" -"use std::collections::HashSet;\n" -"\n" -"use lens_rs::{optics, Lens, LensRef, Optics};\n" -"\n" -"#[derive(Clone, Debug, Lens /* derive to allow lenses to work */)]\n" -"pub struct CreditRecord {\n" -" #[optic(ref)] // macro attribute to allow viewing this field\n" -" customer_id: u64,\n" -" name: String,\n" -" dob: String,\n" -" // other fields omitted\n" -"}\n" -"\n" -"#[derive(Clone, Debug)]\n" -"pub struct Account {\n" -" account_id: u32,\n" -" account_type: String,\n" -" // other fields omitted\n" -"}\n" -"\n" -"#[derive(Clone, Debug, Lens)]\n" -"pub struct AccountRecord {\n" -" #[optic(ref)]\n" -" customer_id: u64,\n" -" accounts: Vec,\n" -"}\n" -"\n" -"fn unique_ids_lens(iter: impl Iterator) -> HashSet\n" -"where\n" -" T: LensRef, // any type with this field\n" -"{\n" -" iter.map(|r| *r.view_ref(optics!(customer_id))).collect()\n" -"}\n" -"```" +#: src/functional/optics.md:405 +msgid "And the trait `Deserialize` implemented by the macros:" +msgstr "" + +#: src/functional/optics.md:415 +msgid "This has been abstract, so let's look at a concrete example." msgstr "" -#: src\functional/lenses.md:149 +#: src/functional/optics.md:417 msgid "" -"The version of `unique_ids_lens` shown here allows any type to be in the " -"iterator,\n" -"so long as it has an attribute called `customer_id` which can be accessed " -"by\n" -"the function.\n" -"This is how most functional programming languages operate on lenses." +"How does actual Serde deserialize a bit of JSON into `struct Concordance` " +"from earlier?" msgstr "" -#: src\functional/lenses.md:154 +#: src/functional/optics.md:420 msgid "" -"Rather than macros, they achieve this with a technique known as " -"\"currying\".\n" -"That is, they \"partially construct\" the function, leaving the type of the\n" -"final parameter (the value being operated on) unfilled until the function " -"is\n" -"called.\n" -"Thus it can be called with different types dynamically even from one place " -"in\n" -"the code.\n" -"That is what the `optics!` and `view_ref` in the example above simulates." +"The user would call a library function to deserialize the data. This would " +"create a `Deserializer` based on the JSON format." msgstr "" -#: src\functional/lenses.md:162 +#: src/functional/optics.md:422 msgid "" -"The functional approach need not be restricted to accessing members.\n" -"More powerful lenses can be created which both _set_ and _get_ data in a\n" -"structure.\n" -"But the concept really becomes interesting when used as a building block " -"for\n" -"composition.\n" -"That is where the concept appears more clearly in Rust." +"Based on the fields in the struct, a `Visitor` would be created (more on " +"that in a moment) which knows how to create each type in a generic data " +"model that was needed to represent it: `Vec` (list), `u64` and `String`." msgstr "" -#: src\functional/lenses.md:169 -msgid "## Prisms: A Higher-Order form of \"Optics\"" +#: src/functional/optics.md:425 +msgid "The deserializer would make calls to the `Visitor` as it parsed items." msgstr "" -#: src\functional/lenses.md:171 +#: src/functional/optics.md:426 msgid "" -"A simple function such as `unique_ids_lens` above operates on a single " -"lens.\n" -"A _prism_ is a function that operates on a _family_ of lenses.\n" -"It is one conceptual level higher, using lenses as a building block, and\n" -"continuing the metaphor, is part of a family of \"optics\".\n" -"It is the main one that is useful in understanding Rust APIs, so will be " -"the\n" -"focus here." +"The `Visitor` would indicate if the items found were expected, and if not, " +"raise an error to indicate deserialization has failed." msgstr "" -#: src\functional/lenses.md:178 -msgid "" -"The same way that traits allow \"lens-like\" design with static polymorphism " -"and\n" -"dynamic dispatch, prism-like designs appear in Rust APIs which split " -"problems\n" -"into multiple associated types to be composed.\n" -"A good example of this is the traits in the parsing crate _Serde_." +#: src/functional/optics.md:429 +msgid "For our very simple structure above, the expected pattern would be:" msgstr "" -#: src\functional/lenses.md:183 +#: src/functional/optics.md:431 msgid "" -"Trying to understand the way _Serde_ works by only reading the API is a\n" -"challenge, especially the first time.\n" -"Consider the `Deserializer` trait, implemented by some type in any library\n" -"which parses a new format:" +"Begin visiting a map (_Serde_'s equivalent to `HashMap` or JSON's " +"dictionary)." msgstr "" -#: src\functional/lenses.md:188 -msgid "" -"```rust,ignore\n" -"pub trait Deserializer<'de>: Sized {\n" -" type Error: Error;\n" -"\n" -" fn deserialize_any(self, visitor: V) -> Result\n" -" where\n" -" V: Visitor<'de>;\n" -"\n" -" fn deserialize_bool(self, visitor: V) -> Result\n" -" where\n" -" V: Visitor<'de>;\n" -"\n" -" // remainder ommitted\n" -"}\n" -"```" +#: src/functional/optics.md:433 +msgid "Visit a string key called \"keys\"." msgstr "" -#: src\functional/lenses.md:204 -msgid "" -"For a trait that is just supposed to parse data from a format and return a\n" -"value, this looks odd." +#: src/functional/optics.md:434 +msgid "Begin visiting a map value." msgstr "" -#: src\functional/lenses.md:207 -msgid "Why are all the return types type erased?" +#: src/functional/optics.md:435 +msgid "For each item, visit a string key then an integer value." msgstr "" -#: src\functional/lenses.md:209 -msgid "" -"To understand that, we need to keep the lens concept in mind and look at\n" -"the definition of the `Visitor` type that is passed in generically:" +#: src/functional/optics.md:436 src/functional/optics.md:443 +msgid "Visit the end of the map." msgstr "" -#: src\functional/lenses.md:212 -msgid "" -"```rust,ignore\n" -"pub trait Visitor<'de>: Sized {\n" -" type Value;\n" -"\n" -" fn visit_bool(self, v: bool) -> Result\n" -" where\n" -" E: Error;\n" -"\n" -" fn visit_u64(self, v: u64) -> Result\n" -" where\n" -" E: Error;\n" -"\n" -" fn visit_str(self, v: &str) -> Result\n" -" where\n" -" E: Error;\n" -"\n" -" // remainder omitted\n" -"}\n" -"```" +#: src/functional/optics.md:437 +msgid "Store the map into the `keys` field of the data structure." msgstr "" -#: src\functional/lenses.md:232 -msgid "" -"The job of the `Visitor` type is to construct values in the _Serde_ data " -"model,\n" -"which are represented by its associated `Value` type." +#: src/functional/optics.md:438 +msgid "Visit a string key called \"value_table\"." msgstr "" -#: src\functional/lenses.md:235 -msgid "" -"These values represent parts of the Rust value being deserialized.\n" -"If this fails, it returns an `Error` type - an error type determined by the\n" -"`Deserializer` when its methods were called." +#: src/functional/optics.md:439 +msgid "Begin visiting a list value." msgstr "" -#: src\functional/lenses.md:239 -msgid "" -"This highlights that `Deserializer` is similar to `CustomerId` from " -"earlier,\n" -"allowing any format parser which implements it to create `Value`s based on " -"what\n" -"it parsed.\n" -"The `Value` trait is acting like a lens in functional programming languages." +#: src/functional/optics.md:440 +msgid "For each item, visit an integer." msgstr "" -#: src\functional/lenses.md:244 -msgid "" -"But unlike the `CustomerId` trait, the return types of `Visitor` methods " -"are\n" -"_generic_, and the concrete `Value` type is _determined by the Visitor " -"itself_." +#: src/functional/optics.md:441 +msgid "Visit the end of the list" msgstr "" -#: src\functional/lenses.md:247 -msgid "" -"Instead of acting as one lens, it effectively acts as a family of\n" -"lenses, one for each concrete type of `Visitor`." +#: src/functional/optics.md:442 +msgid "Store the list into the `value_table` field." msgstr "" -#: src\functional/lenses.md:250 +#: src/functional/optics.md:445 +msgid "But what determines which \"observation\" pattern is expected?" +msgstr "" + +#: src/functional/optics.md:447 msgid "" -"The `Deserializer` API is based on having a generic set of \"lenses\" work " -"across\n" -"a set of other generic types for \"observation\".\n" -"It is a _prism_." +"A functional programming language would be able to use currying to create " +"reflection of each type based on the type itself. Rust does not support " +"that, so every single type would need to have its own code written based on " +"its fields and their properties." msgstr "" -#: src\functional/lenses.md:254 -msgid "For example, consider the identity record from earlier but simplified:" +#: src/functional/optics.md:452 +msgid "_Serde_ solves this usability challenge with a derive macro:" msgstr "" -#: src\functional/lenses.md:256 +#: src/functional/optics.md:464 msgid "" -"```json\n" -"{ \"name\": \"Jane Doe\",\n" -" \"customer_id\": 1048576332,\n" -"}\n" -"```" +"That macro simply generates an impl block causing the struct to implement a " +"trait called `Deserialize`." msgstr "" -#: src\functional/lenses.md:262 +#: src/functional/optics.md:467 msgid "" -"How would the _Serde_ library deserialize this JSON into `struct " -"CreditRecord`?" +"This is the function that determines how to create the struct itself. Code " +"is generated based on the struct's fields. When the parsing library is " +"called - in our example, a JSON parsing library - it creates a " +"`Deserializer` and calls `Type::deserialize` with it as a parameter." msgstr "" -#: src\functional/lenses.md:264 +#: src/functional/optics.md:472 msgid "" -"1. The user would call a library function to deserialize the data. This " -"would\n" -" create a `Deserializer` based on the JSON format.\n" -"1. Based on the fields in the struct, a `Visitor` would be created (more on\n" -" that in a moment) which knows how to create each type in a generic data\n" -" model that was needed to represent it: `u64` and `String`.\n" -"1. The deserializer would make calls to the `Visitor` as it parsed items.\n" -"1. The `Visitor` would indicate if the items found were expected, and if " -"not,\n" -" raise an error to indicate deserialization has failed." +"The `deserialize` code will then create a `Visitor` which will have its " +"calls \"refracted\" by the `Deserializer`. If everything goes well, " +"eventually that `Visitor` will construct a value corresponding to the type " +"being parsed and return it." msgstr "" -#: src\functional/lenses.md:273 -msgid "For our very simple structure above, the expected pattern would be:" +#: src/functional/optics.md:477 +msgid "" +"For a complete example, see the [_Serde_ documentation](https://serde.rs/" +"deserialize-struct.html)." msgstr "" -#: src\functional/lenses.md:275 +#: src/functional/optics.md:480 msgid "" -"1. Visit a map (_Serde_'s equvialent to `HashMap` or JSON's dictionary).\n" -"1. Visit a string key called \"name\".\n" -"1. Visit a string value, which will go into the `name` field.\n" -"1. Visit a string key called \"customer_id\".\n" -"1. Visit a string value, which will go into the `customer_id` field.\n" -"1. Visit the end of the map." +"The result is that types to be deserialized only implement the \"top layer\" " +"of the API, and file formats only need to implement the \"bottom layer\". " +"Each piece can then \"just work\" with the rest of the ecosystem, since " +"generic types will bridge them." msgstr "" -#: src\functional/lenses.md:282 -msgid "But what determines which \"observation\" pattern is expected?" +#: src/functional/optics.md:485 +msgid "" +"In conclusion, Rust's generic-inspired type system can bring it close to " +"these concepts and use their power, as shown in this API design. But it may " +"also need procedural macros to create bridges for its generics." msgstr "" -#: src\functional/lenses.md:284 +#: src/functional/optics.md:489 msgid "" -"A functional programming language would be able to use currying to create\n" -"reflection of each type based on the type itself.\n" -"Rust does not support that, so every single type would need to have its own\n" -"code written based on its fields and their properties." +"If you are interested in learning more about this topic, please check the " +"following section." msgstr "" -#: src\functional/lenses.md:289 -msgid "_Serde_ solves this usability challenge with a derive macro:" +#: src/functional/optics.md:492 +msgid "See Also" msgstr "" -#: src\functional/lenses.md:291 +#: src/functional/optics.md:494 msgid "" -"```rust,ignore\n" -"use serde::Deserialize;\n" -"\n" -"#[derive(Deserialize)]\n" -"struct IdRecord {\n" -" name: String,\n" -" customer_id: String,\n" -"}\n" -"```" +"[lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses " +"implementation, with a cleaner interface than these examples" msgstr "" -#: src\functional/lenses.md:301 +#: src/functional/optics.md:496 msgid "" -"That macro simply generates an impl block causing the struct to implement a\n" -"trait called `Deserialize`." +"[Serde](https://serde.rs) itself, which makes these concepts intuitive for " +"end users (i.e. defining the structs) without needing to understand the " +"details" msgstr "" -#: src\functional/lenses.md:304 -msgid "It is defined this way:" +#: src/functional/optics.md:498 +msgid "" +"[luminance](https://github.com/phaazon/luminance-rs) is a crate for drawing " +"computer graphics that uses similar API design, including procedural macros " +"to create full prisms for buffers of different pixel types that remain " +"generic" msgstr "" -#: src\functional/lenses.md:306 +#: src/functional/optics.md:501 msgid "" -"```rust,ignore\n" -"pub trait Deserialize<'de>: Sized {\n" -" fn deserialize(deserializer: D) -> Result\n" -" where\n" -" D: Deserializer<'de>;\n" -"}\n" -"```" +"[An Article about Lenses in Scala](https://web.archive.org/web/" +"20221128185849/https://medium.com/zyseme-technology/functional-references-" +"lens-and-other-optics-in-scala-e5f7e2fdafe) that is very readable even " +"without Scala expertise." msgstr "" -#: src\functional/lenses.md:314 +#: src/functional/optics.md:503 msgid "" -"This is the function that determines how to create the struct itself.\n" -"Code is generated based on the struct's fields.\n" -"When the parsing library is called - in our example, a JSON parsing library " -"-\n" -"it creates a `Deserializer` and calls `Type::deserialize` with it as a\n" -"parameter." +"[Paper: Profunctor Optics: Modular Data Accessors](https://web.archive.org/" +"web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf)" msgstr "" -#: src\functional/lenses.md:320 +#: src/functional/optics.md:505 msgid "" -"The `deserialize` code will then create a `Visitor` which will have its " -"calls\n" -"\"refracted\" by the `Deserializer`.\n" -"If everything goes well, eventually that `Visitor` will construct a value\n" -"corresponding to the type being parsed and return it." +"[Musli](https://github.com/udoprog/musli) is a library which attempts to use " +"a similar structure with a different approach, e.g. doing away with the " +"visitor" msgstr "" -#: src\functional/lenses.md:325 +#: src/functional/optics.md:508 msgid "" -"For a complete example, see the [_Serde_ documentation](https://serde.rs/" -"deserialize-struct.html)." +"[School of Haskell: A Little Lens Starter Tutorial](https://web.archive.org/" +"web/20221128190041/https://www.schoolofhaskell.com/school/to-infinity-and-" +"beyond/pick-of-the-week/a-little-lens-starter-tutorial)" msgstr "" -#: src\functional/lenses.md:327 -msgid "To wrap up, this is the power of _Serde_:" +#: src/functional/optics.md:510 +msgid "" +"[Concordance on Wikipedia](https://en.wikipedia.org/wiki/" +"Concordance_(publishing))" msgstr "" -#: src\functional/lenses.md:329 -msgid "" -"1. The structure being parsed is represented by an `impl` block for " -"`Deserialize`\n" -"1. The input data format (e.g. JSON) is represented by a `Deserializer` " -"called\n" -" by `Deserialize`\n" -"1. The `Deserializer` acts like a prism which \"refracts\" lens-like " -"`Visitor`\n" -" calls which actually build the data value" +#: src/additional_resources/index.md:1 +msgid "Additional resources" msgstr "" -#: src\functional/lenses.md:335 -msgid "" -"The result is that types to be deserialized only implement the \"top layer\" " -"of\n" -"the API, and file formats only need to implement the \"bottom layer\".\n" -"Each piece can then \"just work\" with the rest of the ecosystem, since " -"generic\n" -"types will bridge them." +#: src/additional_resources/index.md:3 +msgid "A collection of complementary helpful content" msgstr "" -#: src\functional/lenses.md:340 -msgid "" -"To emphasize, the only reason this model works on any format and any type " -"is\n" -"because the `Deserializer` trait's output type **is specified by the\n" -"implementor of `Visitor` it is passed**, rather than being tied to one " -"specific\n" -"type.\n" -"This was not true in the account example earlier." +#: src/additional_resources/index.md:5 +msgid "Talks" msgstr "" -#: src\functional/lenses.md:346 +#: src/additional_resources/index.md:7 msgid "" -"Rust's generic-inspired type system can bring it close to these concepts " -"and\n" -"use their power, as shown in this API design.\n" -"But it may also need procedural macros to create bridges for its generics." +"[Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by " +"Nicholas Cameron at the PDRust (2016)" msgstr "" -#: src\functional/lenses.md:350 -msgid "## See Also" +#: src/additional_resources/index.md:9 +msgid "" +"[Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?" +"v=0zOg8_B71gE) by Pascal Hertleif at RustFest (2017)" msgstr "" -#: src\functional/lenses.md:352 +#: src/additional_resources/index.md:11 msgid "" -"- [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses\n" -" implementation, with a cleaner interface than these examples\n" -"- [serde](https://serde.rs) itself, which makes these concepts intuitive " -"for\n" -" end users (i.e. defining the structs) without needing to undestand the\n" -" details\n" -"- [luminance](https://github.com/phaazon/luminance-rs) is a crate for " -"drawing\n" -" computer graphics that uses lens API design, including proceducal macros " -"to\n" -" create full prisms for buffers of different pixel types that remain " -"generic\n" -"- [An Article about Lenses in Scala](https://web.archive.org/web/" -"20221128185849/https://medium.com/zyseme-technology/functional-references-" -"lens-and-other-optics-in-scala-e5f7e2fdafe)\n" -" that is very readable even without Scala expertise.\n" -"- [Paper: Profunctor Optics: Modular Data\n" -" Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/" -"ftp/arxiv/papers/1703/1703.10857.pdf)" +"[Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) " +"by Nicholas Cameron at LinuxConfAu (2018)" msgstr "" -#: src\functional/lenses.md:365 -msgid "" -"[School of Haskell: A Little Lens Starter Tutorial](https://web.archive.org/" -"web/20221128190041/https://www.schoolofhaskell.com/school/to-infinity-and-" -"beyond/pick-of-the-week/a-little-lens-starter-tutorial)" +#: src/additional_resources/index.md:14 +msgid "Books (Online)" msgstr "" -#: src\additional_resources/index.md:1 -msgid "# Additional resources" +#: src/additional_resources/index.md:16 +msgid "[The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" msgstr "" -#: src\additional_resources/index.md:3 -msgid "A collection of complementary helpful content" +#: src/additional_resources/design-principles.md:3 +msgid "A brief overview over common design principles" msgstr "" -#: src\additional_resources/index.md:5 -msgid "## Talks" +#: src/additional_resources/design-principles.md:7 +msgid "[SOLID](https://en.wikipedia.org/wiki/SOLID)" msgstr "" -#: src\additional_resources/index.md:7 +#: src/additional_resources/design-principles.md:9 msgid "" -"- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by\n" -" Nicholas Cameron at the PDRust (2016)\n" -"- [Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?" -"v=0zOg8_B71gE)\n" -" by Pascal Hertleif at RustFest (2017)\n" -"- [Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) " -"by\n" -" Nicholas Cameron at LinuxConfAu (2018)" +"[Single Responsibility Principle (SRP)](https://en.wikipedia.org/wiki/Single-" +"responsibility_principle): A class should only have a single responsibility, " +"that is, only changes to one part of the software's specification should be " +"able to affect the specification of the class." msgstr "" -#: src\additional_resources/index.md:14 -msgid "## Books (Online)" +#: src/additional_resources/design-principles.md:13 +msgid "" +"[Open/Closed Principle (OCP)](https://en.wikipedia.org/wiki/" +"Open%E2%80%93closed_principle): \"Software entities ... should be open for " +"extension, but closed for modification.\"" msgstr "" -#: src\additional_resources/index.md:16 -msgid "- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" +#: src/additional_resources/design-principles.md:16 +msgid "" +"[Liskov Substitution Principle (LSP)](https://en.wikipedia.org/wiki/" +"Liskov_substitution_principle): \"Objects in a program should be replaceable " +"with instances of their subtypes without altering the correctness of that " +"program.\"" msgstr "" -#: src\additional_resources/design-principles.md:1 -msgid "# Design principles" +#: src/additional_resources/design-principles.md:19 +msgid "" +"[Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/" +"Interface_segregation_principle): \"Many client-specific interfaces are " +"better than one general-purpose interface.\"" msgstr "" -#: src\additional_resources/design-principles.md:3 -msgid "## A brief overview over common design principles" +#: src/additional_resources/design-principles.md:22 +msgid "" +"[Dependency Inversion Principle (DIP)](https://en.wikipedia.org/wiki/" +"Dependency_inversion_principle): One should \"depend upon abstractions, \\" +"[not\\] concretions.\"" msgstr "" -#: src\additional_resources/design-principles.md:7 -msgid "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" +#: src/additional_resources/design-principles.md:25 +msgid "" +"[CRP (Composite Reuse Principle) or Composition over inheritance](https://" +"en.wikipedia.org/wiki/Composition_over_inheritance)" msgstr "" -#: src\additional_resources/design-principles.md:9 +#: src/additional_resources/design-principles.md:27 msgid "" -"- [Single Responsibility Principle (SRP)](https://en.wikipedia.org/wiki/" -"Single-responsibility_principle):\n" -" A class should only have a single responsibility, that is, only changes " -"to\n" -" one part of the software's specification should be able to affect the\n" -" specification of the class.\n" -"- [Open/Closed Principle (OCP)](https://en.wikipedia.org/wiki/" -"Open%E2%80%93closed_principle):\n" -" \"Software entities ... should be open for extension, but closed for\n" -" modification.\"\n" -"- [Liskov Substitution Principle (LSP)](https://en.wikipedia.org/wiki/" -"Liskov_substitution_principle):\n" -" \"Objects in a program should be replaceable with instances of their " -"subtypes\n" -" without altering the correctness of that program.\"\n" -"- [Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/" -"Interface_segregation_principle):\n" -" \"Many client-specific interfaces are better than one general-purpose\n" -" interface.\"\n" -"- [Dependency Inversion Principle (DIP)](https://en.wikipedia.org/wiki/" -"Dependency_inversion_principle):\n" -" One should \"depend upon abstractions, [not] concretions.\"" +"“a the principle that classes should favor polymorphic behavior and code " +"reuse by their composition (by containing instances of other classes that " +"implement the desired functionality) over inheritance from a base or parent " +"class” - Knoernschild, Kirk (2002). Java Design - Objects, UML, and Process" msgstr "" -#: src\additional_resources/design-principles.md:25 +#: src/additional_resources/design-principles.md:32 msgid "" -"## [DRY (Don’t Repeat Yourself)](https://en.wikipedia.org/wiki/" +"[DRY (Don’t Repeat Yourself)](https://en.wikipedia.org/wiki/" "Don%27t_repeat_yourself)" msgstr "" -#: src\additional_resources/design-principles.md:27 +#: src/additional_resources/design-principles.md:34 msgid "" -"\"Every piece of knowledge must have a single, unambiguous, authoritative\n" +"\"Every piece of knowledge must have a single, unambiguous, authoritative " "representation within a system\"" msgstr "" -#: src\additional_resources/design-principles.md:30 -msgid "## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" +#: src/additional_resources/design-principles.md:37 +msgid "[KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" msgstr "" -#: src\additional_resources/design-principles.md:32 +#: src/additional_resources/design-principles.md:39 msgid "" -"most systems work best if they are kept simple rather than made " -"complicated;\n" -"therefore, simplicity should be a key goal in design, and unnecessary\n" +"most systems work best if they are kept simple rather than made complicated; " +"therefore, simplicity should be a key goal in design, and unnecessary " "complexity should be avoided" msgstr "" -#: src\additional_resources/design-principles.md:36 -msgid "## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" +#: src/additional_resources/design-principles.md:43 +msgid "[Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" msgstr "" -#: src\additional_resources/design-principles.md:38 +#: src/additional_resources/design-principles.md:45 msgid "" -"a given object should assume as little as possible about the structure or\n" +"a given object should assume as little as possible about the structure or " "properties of anything else (including its subcomponents), in accordance " -"with\n" -"the principle of \"information hiding\"" +"with the principle of \"information hiding\"" msgstr "" -#: src\additional_resources/design-principles.md:42 +#: src/additional_resources/design-principles.md:49 msgid "" -"## [Design by contract (DbC)](https://en.wikipedia.org/wiki/" -"Design_by_contract)" +"[Design by contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" msgstr "" -#: src\additional_resources/design-principles.md:44 +#: src/additional_resources/design-principles.md:51 msgid "" -"software designers should define formal, precise and verifiable interface\n" +"software designers should define formal, precise and verifiable interface " "specifications for software components, which extend the ordinary definition " -"of\n" -"abstract data types with preconditions, postconditions and invariants" +"of abstract data types with preconditions, postconditions and invariants" msgstr "" -#: src\additional_resources/design-principles.md:48 +#: src/additional_resources/design-principles.md:55 msgid "" -"## [Encapsulation](https://en.wikipedia.org/wiki/" +"[Encapsulation](https://en.wikipedia.org/wiki/" "Encapsulation_(computer_programming))" msgstr "" -#: src\additional_resources/design-principles.md:50 +#: src/additional_resources/design-principles.md:57 msgid "" "bundling of data with the methods that operate on that data, or the " -"restricting\n" -"of direct access to some of an object's components. Encapsulation is used " -"to\n" -"hide the values or state of a structured data object inside a class, " -"preventing\n" -"unauthorized parties' direct access to them." +"restricting of direct access to some of an object's components. " +"Encapsulation is used to hide the values or state of a structured data " +"object inside a class, preventing unauthorized parties' direct access to " +"them." msgstr "" -#: src\additional_resources/design-principles.md:55 +#: src/additional_resources/design-principles.md:62 msgid "" -"## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/" +"[Command-Query-Separation (CQS)](https://en.wikipedia.org/wiki/" "Command%E2%80%93query_separation)" msgstr "" -#: src\additional_resources/design-principles.md:57 +#: src/additional_resources/design-principles.md:64 msgid "" -"“Functions should not produce abstract side effects...only commands\n" -"(procedures) will be permitted to produce side effects.” - Bertrand Meyer:\n" +"“Functions should not produce abstract side effects...only commands " +"(procedures) will be permitted to produce side effects.” - Bertrand Meyer: " "Object-Oriented Software Construction" msgstr "" -#: src\additional_resources/design-principles.md:61 +#: src/additional_resources/design-principles.md:68 msgid "" -"## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/" +"[Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/" "Principle_of_least_astonishment)" msgstr "" -#: src\additional_resources/design-principles.md:63 +#: src/additional_resources/design-principles.md:70 msgid "" "a component of a system should behave in a way that most users will expect " -"it\n" -"to behave. The behavior should not astonish or surprise users" +"it to behave. The behavior should not astonish or surprise users" msgstr "" -#: src\additional_resources/design-principles.md:66 -msgid "## Linguistic-Modular-Units" +#: src/additional_resources/design-principles.md:73 +msgid "Linguistic-Modular-Units" msgstr "" -#: src\additional_resources/design-principles.md:68 +#: src/additional_resources/design-principles.md:75 msgid "" "“Modules must correspond to syntactic units in the language used.” - " -"Bertrand\n" -"Meyer: Object-Oriented Software Construction" +"Bertrand Meyer: Object-Oriented Software Construction" msgstr "" -#: src\additional_resources/design-principles.md:71 -msgid "## Self-Documentation" +#: src/additional_resources/design-principles.md:78 +msgid "Self-Documentation" msgstr "" -#: src\additional_resources/design-principles.md:73 +#: src/additional_resources/design-principles.md:80 msgid "" -"“The designer of a module should strive to make all information about the\n" +"“The designer of a module should strive to make all information about the " "module part of the module itself.” - Bertrand Meyer: Object-Oriented " -"Software\n" -"Construction" +"Software Construction" msgstr "" -#: src\additional_resources/design-principles.md:77 -msgid "## Uniform-Access" +#: src/additional_resources/design-principles.md:84 +msgid "Uniform-Access" msgstr "" -#: src\additional_resources/design-principles.md:79 +#: src/additional_resources/design-principles.md:86 msgid "" -"“All services offered by a module should be available through a uniform\n" +"“All services offered by a module should be available through a uniform " "notation, which does not betray whether they are implemented through storage " -"or\n" -"through computation.” - Bertrand Meyer: Object-Oriented Software Construction" +"or through computation.” - Bertrand Meyer: Object-Oriented Software " +"Construction" msgstr "" -#: src\additional_resources/design-principles.md:83 -msgid "## Single-Choice" +#: src/additional_resources/design-principles.md:90 +msgid "Single-Choice" msgstr "" -#: src\additional_resources/design-principles.md:85 +#: src/additional_resources/design-principles.md:92 msgid "" -"“Whenever a software system must support a set of alternatives, one and " -"only\n" +"“Whenever a software system must support a set of alternatives, one and only " "one module in the system should know their exhaustive list.” - Bertrand " -"Meyer:\n" -"Object-Oriented Software Construction" +"Meyer: Object-Oriented Software Construction" msgstr "" -#: src\additional_resources/design-principles.md:89 -msgid "## Persistence-Closure" +#: src/additional_resources/design-principles.md:96 +msgid "Persistence-Closure" msgstr "" -#: src\additional_resources/design-principles.md:91 +#: src/additional_resources/design-principles.md:98 msgid "" -"“Whenever a storage mechanism stores an object, it must store with it the\n" -"dependents of that object. Whenever a retrieval mechanism retrieves a\n" -"previously stored object, it must also retrieve any dependent of that " -"object\n" -"that has not yet been retrieved.” - Bertrand Meyer: Object-Oriented " -"Software\n" +"“Whenever a storage mechanism stores an object, it must store with it the " +"dependents of that object. Whenever a retrieval mechanism retrieves a " +"previously stored object, it must also retrieve any dependent of that object " +"that has not yet been retrieved.” - Bertrand Meyer: Object-Oriented Software " "Construction" msgstr "" From b2d609031657ab9561b88bed9302ecf5042d5b43 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Sat, 17 May 2025 23:50:45 +0900 Subject: [PATCH 03/12] Japanese translation: Idioms / Use borrowed types for arguments --- po/ja.po | 110 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/po/ja.po b/po/ja.po index b66262f7..707fb76d 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-17 14:53+0900\n" +"PO-Revision-Date: 2025-05-17 23:49+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -26,11 +26,11 @@ msgstr "翻訳" #: src/SUMMARY.md:5 src/idioms/index.md:1 msgid "Idioms" -msgstr "慣習" +msgstr "イディオム" #: src/SUMMARY.md:6 src/idioms/coercion-arguments.md:1 msgid "Use borrowed types for arguments" -msgstr "引数には借用型を使う" +msgstr "引数に借用型を使う" #: src/SUMMARY.md:7 msgid "Concatenating Strings with format!" @@ -54,7 +54,7 @@ msgstr "デストラクタでの後処理" #: src/SUMMARY.md:12 msgid "`mem::{take(_), replace(_)}`" -msgstr "" +msgstr "`mem::{take(_), replace(_)}`" #: src/SUMMARY.md:13 src/idioms/on-stack-dyn-dispatch.md:1 msgid "On-Stack Dynamic Dispatch" @@ -305,9 +305,9 @@ msgid "" "social norms of the community. You should break them only if you have a good " "reason for it." msgstr "" -"[慣習](./idioms/index.md): コーディングにおいて推奨される書き方。コミュニティ" -"内の社会的規範。慣習は破っても構いませんが、きちんと理由がある場合に限りま" -"す。" +"[イディオム](./idioms/index.md): コーディングにおいて推奨される書き方。コミュ" +"ニティ内の社会的規範。慣習は破っても構いませんが、きちんと理由がある場合に限" +"ります。" #: src/intro.md:42 msgid "" @@ -332,6 +332,8 @@ msgid "" "https://web.archive.org/web/20240124025806/https://www.infoq.com/podcasts/" "software-architecture-hard-parts/" msgstr "" +"https://web.archive.org/web/20240124025806/https://www.infoq.com/podcasts/" +"software-architecture-hard-parts/" #: src/translations.md:3 msgid "" @@ -351,7 +353,7 @@ msgstr "外部の翻訳" #: src/translations.md:10 msgid "[简体中文](https://fomalhauthmj.github.io/patterns/)" -msgstr "" +msgstr "[简体中文](https://fomalhauthmj.github.io/patterns/)" #: src/translations.md:12 msgid "" @@ -368,6 +370,10 @@ msgid "" "idiomatic code allows other developers to understand better what is " "happening." msgstr "" +"[イディオム](https://en.wikipedia.org/wiki/Programming_idiom)とは、コミュニ" +"ティの中で広く合意されている、よく使われる書き方やスタイル、設計指針のことで" +"す。イディオムに則ったコードを書くことで、他の開発者がコードの意図をより理解" +"しやすくなります。" #: src/idioms/index.md:7 msgid "" @@ -376,6 +382,9 @@ msgid "" "developer. So, since we have this abstraction layer, why not make it more " "readable?" msgstr "" +"最終的にコンピュータが気にするのは、コンパイラによって生成される機械語だけで" +"す。ソースコードはむしろ、開発者のための情報です。せっかくある抽象化レイヤー" +"ならば、それを活かして読みやすくする方がお得ですよね?" #: src/idioms/index.md:11 msgid "" @@ -384,10 +393,14 @@ msgid "" "are kept simple rather than made complicated; therefore, simplicity should " "be a key goal in design, and unnecessary complexity should be avoided\"." msgstr "" +"ここで思い出したいのが [KISS原則](https://en.wikipedia.org/wiki/" +"KISS_principle)(Keep It Simple, Stupid) です。これは「システムは複雑にする" +"よりも、シンプルに保つ方がうまく機能する。したがって、設計ではシンプルさを最" +"優先し、不要な複雑さは避けるべきである」という考え方です。" #: src/idioms/index.md:16 msgid "Code is there for humans, not computers, to understand." -msgstr "" +msgstr "Code is there for humans, not computers, to understand." #: src/idioms/coercion-arguments.md:3 src/idioms/concat-format.md:3 #: src/idioms/ctor.md:3 src/idioms/default.md:3 src/idioms/deref.md:3 @@ -410,7 +423,7 @@ msgstr "" #: src/anti_patterns/deny-warnings.md:3 src/anti_patterns/deref.md:3 #: src/functional/generics-type-classes.md:3 msgid "Description" -msgstr "" +msgstr "概要" #: src/idioms/coercion-arguments.md:5 msgid "" @@ -418,6 +431,9 @@ msgid "" "when you are deciding which argument type to use for a function argument. In " "this way, the function will accept more input types." msgstr "" +"関数の引数としてどの型を使うか検討する際、derefによる型強制の対象となる型を使" +"うことで、コードの柔軟性を高めることができます。これにより、関数がより多くの" +"入力型を受け取れるようになります。" #: src/idioms/coercion-arguments.md:9 msgid "" @@ -425,6 +441,10 @@ msgid "" "always prefer using the **borrowed type** over **borrowing the owned type**. " "Such as `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`." msgstr "" +"これは、スライス可能な型やファットポインタ型に限定されるものではありません。" +"むしろ、**所有型の借用**よりも、**借用型**を使うことを基本と考えるべきです。" +"`&String` よりも `&str`、`&Vec` よりも `&[T]`、`&Box` よりも `&T` のよ" +"うにです。" #: src/idioms/coercion-arguments.md:13 msgid "" @@ -434,6 +454,11 @@ msgid "" "of indirection. We can avoid this by using `&str` instead, and letting " "`&String` coerce to a `&str` whenever the function is invoked." msgstr "" +"借用型を使うことで、間接的な層を含んでいる所有型に対して、さらに間接的な層を" +"重ねてしまう状況を避けることができます。たとえば、`String` はすでにヒープ上の" +"データを指す間接的な層を持っているので、`&String` は二段階の層を持ちます。こ" +"のような冗長さを避けるには、`&str` を使い、関数の呼び出し時に `&String` を " +"`&str` に型強制(coercion)させるのが有効です。" #: src/idioms/coercion-arguments.md:19 src/idioms/concat-format.md:10 #: src/idioms/default.md:20 src/idioms/deref.md:9 src/idioms/dtor-finally.md:9 @@ -450,7 +475,7 @@ msgstr "" #: src/anti_patterns/borrow_clone.md:11 src/anti_patterns/deny-warnings.md:8 #: src/anti_patterns/deref.md:8 src/functional/generics-type-classes.md:38 msgid "Example" -msgstr "" +msgstr "例" #: src/idioms/coercion-arguments.md:21 msgid "" @@ -458,6 +483,9 @@ msgid "" "a function argument versus using a `&str`, but the ideas apply as well to " "using `&Vec` versus using a `&[T]` or using a `&Box` versus a `&T`." msgstr "" +"ここでは、関数の引数として `&String` を使う場合と `&str` を使う場合の違いを例" +"に挙げて説明します。この考え方は、`&Vec` と `&[T]`、あるいは `&Box` と " +"`&T` の使い分けにも同様に当てはまります。" #: src/idioms/coercion-arguments.md:25 msgid "" @@ -465,42 +493,44 @@ msgid "" "consecutive vowels. We don't need to own the string to determine this, so we " "will take a reference." msgstr "" +"ある単語に3つの母音が連続して含まれているかどうかを判定したい場合を考えます。" +"この処理のために文字列の所有権は必要なく、参照を受け取るだけで十分です。" #: src/idioms/coercion-arguments.md:29 msgid "The code might look something like this:" -msgstr "" +msgstr "そのときのコードは、次のようになるでしょう:" #: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 msgid "'a'" -msgstr "" +msgstr "'a'" #: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 msgid "'e'" -msgstr "" +msgstr "'e'" #: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 msgid "'i'" -msgstr "" +msgstr "'i'" #: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 msgid "'o'" -msgstr "" +msgstr "'o'" #: src/idioms/coercion-arguments.md:36 src/idioms/coercion-arguments.md:96 msgid "'u'" -msgstr "" +msgstr "'u'" #: src/idioms/coercion-arguments.md:49 msgid "\"Ferris\"" -msgstr "" +msgstr "\"Ferris\"" #: src/idioms/coercion-arguments.md:50 msgid "\"Curious\"" -msgstr "" +msgstr "\"Curious\"" #: src/idioms/coercion-arguments.md:51 src/idioms/coercion-arguments.md:52 msgid "\"{}: {}\"" -msgstr "" +msgstr "\"{}: {}\"" #: src/idioms/coercion-arguments.md:54 msgid "" @@ -508,6 +538,9 @@ msgid "" " // println!(\"Ferris: {}\", three_vowels(\"Ferris\"));\n" " // println!(\"Curious: {}\", three_vowels(\"Curious\"));\n" msgstr "" +"// これは正常に動作しますが、次の2行は失敗します:\n" +" // println!(\"Ferris: {}\", three_vowels(\"Ferris\"));\n" +" // println!(\"Curious: {}\", three_vowels(\"Curious\"));\n" #: src/idioms/coercion-arguments.md:60 msgid "" @@ -516,14 +549,19 @@ msgid "" "because a `&str` type will not coerce to a `&String` type. We can fix this " "by simply modifying the type for our argument." msgstr "" +"これは `&String` 型を引数に渡しているため、問題なく動作します。しかし、最後の" +"2行のコメントを外すと、この例はコンパイルエラーになります。これは、`&str` 型" +"は `&String` 型には自動で型強制されないためです。この問題は、引数の型を少し変" +"更するだけで解決できます。" #: src/idioms/coercion-arguments.md:65 msgid "For instance, if we change our function declaration to:" -msgstr "" +msgstr "具体的には、関数を次のように書き換えます:" #: src/idioms/coercion-arguments.md:71 msgid "then both versions will compile and print the same output." msgstr "" +"こうすれば、どちらの呼び出し方法でもコンパイルが通り、同じ出力が得られます。" #: src/idioms/coercion-arguments.md:78 msgid "" @@ -533,6 +571,10 @@ msgid "" "ignoring this special example, you may still find that using `&str` will " "give you more flexibility than using a `&String`." msgstr "" +"話はここで終わりではありません。もしかするとあなたは「そんなの関係ない。どう" +"せ 'static str を引数に渡す(今回 \"Ferris\" を使ったような)ことなんてない" +"し。」と思っているかもしれません。ですが、たとえこの特殊な例を無視したとして" +"も、&str を使う方が &String より柔軟性が高い場面は他にもあります。" #: src/idioms/coercion-arguments.md:84 msgid "" @@ -541,28 +583,32 @@ msgid "" "vowels. We probably should make use of the function we have already defined " "and simply feed in each word from the sentence." msgstr "" +"次の例では、文章全体を受け取り、その文章の中に3つ連続した母音が含まれる単語が" +"あるか判定することを考えてみましょう。先ほど定義した関数を再利用して、文の中" +"の各単語を入力すれば済むはずです。" #: src/idioms/coercion-arguments.md:89 msgid "An example of this could look like this:" -msgstr "" +msgstr "そのときのコードは、次のようになるでしょう:" #: src/idioms/coercion-arguments.md:110 msgid "\"Once upon a time, there was a friendly curious crab named Ferris\"" -msgstr "" +msgstr "\"Once upon a time, there was a friendly curious crab named Ferris\"" #: src/idioms/coercion-arguments.md:111 msgid "' '" -msgstr "" +msgstr "' '" #: src/idioms/coercion-arguments.md:113 msgid "\"{word} has three consecutive vowels!\"" -msgstr "" +msgstr "\"{word} has three consecutive vowels!\"" #: src/idioms/coercion-arguments.md:119 msgid "" "Running this example using our function declared with an argument type " "`&str` will yield" msgstr "" +"この例を、引数の型が &str の関数で実行すると、次のような出力が得られます" #: src/idioms/coercion-arguments.md:126 msgid "" @@ -572,6 +618,10 @@ msgid "" "which is not implicit, whereas converting from `String` to `&str` is cheap " "and implicit." msgstr "" +"しかし、関数の引数を `&String` にしている場合、この例は動作しません。これは、" +"文字列スライスは `&str` 型であって、`&String` ではないからです。`&String` に" +"変換するにはヒープ確保が必要になり、暗黙的には行われません。一方で、`String` " +"から `&str` への変換は安価で暗黙的に行われます。" #: src/idioms/coercion-arguments.md:132 src/idioms/ctor.md:101 #: src/idioms/default.md:58 src/idioms/deref.md:76 @@ -588,13 +638,15 @@ msgstr "" #: src/anti_patterns/borrow_clone.md:65 src/anti_patterns/deny-warnings.md:101 #: src/anti_patterns/deref.md:124 src/functional/generics-type-classes.md:236 msgid "See also" -msgstr "" +msgstr "関連資料" #: src/idioms/coercion-arguments.md:134 msgid "" "[Rust Language Reference on Type Coercions](https://doc.rust-lang.org/" "reference/type-coercions.html)" msgstr "" +"[Rust Language Reference on Type Coercions](https://doc.rust-lang.org/" +"reference/type-coercions.html)" #: src/idioms/coercion-arguments.md:135 msgid "" @@ -603,12 +655,18 @@ msgid "" "hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html) by Herman " "J. Radtke III" msgstr "" +"`String` と `&str` の扱いについてもっと知りたい方は、Herman J. Radtke III に" +"よる [ブログシリーズ(2015)](https://web.archive.org/web/20201112023149/" +"https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html) を" +"参照してください" #: src/idioms/coercion-arguments.md:138 msgid "" "[Steve Klabnik's Blogpost on 'When should I use String vs &str?'](https://" "archive.ph/LBpD0)" msgstr "" +"[Steve Klabnik's Blogpost on 'When should I use String vs &str?'](https://" +"archive.ph/LBpD0)" #: src/idioms/concat-format.md:1 #, fuzzy From f0a8fce3c413200430ae65de49c2bca5621ab2ce Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Mon, 19 May 2025 08:52:30 +0900 Subject: [PATCH 04/12] Japanese translation: Concatenating strings with format! --- po/ja.po | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/po/ja.po b/po/ja.po index 707fb76d..80187b60 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-17 23:49+0900\n" +"PO-Revision-Date: 2025-05-19 08:50+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -669,9 +669,8 @@ msgstr "" "archive.ph/LBpD0)" #: src/idioms/concat-format.md:1 -#, fuzzy msgid "Concatenating strings with `format!`" -msgstr "format! による文字列連結" +msgstr "`format!` による文字列連結" #: src/idioms/concat-format.md:5 msgid "" @@ -680,6 +679,10 @@ msgid "" "convenient to use `format!`, especially where there is a mix of literal and " "non-literal strings." msgstr "" +"文字列を組み立てる方法として、可変な `String` に対して `push` や `push_str` " +"メソッドを使ったり、`+` 演算子を使うこともできます。しかし、リテラル文字列と" +"リテラルでない文字列を混ぜて扱いたい場合には、`format!` マクロを使った方が便" +"利なことが多くあります。" #: src/idioms/concat-format.md:14 msgid "" @@ -689,14 +692,19 @@ msgid "" " // result.push('!');\n" " // result\n" msgstr "" +"// result 文字列を手動で構築することもできます。\n" +" // let mut result = \"Hello \".to_owned();\n" +" // result.push_str(name);\n" +" // result.push('!');\n" +" // result\n" #: src/idioms/concat-format.md:20 msgid "// But using format! is better.\n" -msgstr "" +msgstr "// しかし、format! を使った方が簡潔です。\n" #: src/idioms/concat-format.md:21 msgid "\"Hello {name}!\"" -msgstr "" +msgstr "\"Hello {name}!\"" #: src/idioms/concat-format.md:25 src/idioms/deref.md:43 #: src/idioms/dtor-finally.md:46 src/idioms/mem-replace.md:91 @@ -714,13 +722,14 @@ msgstr "" #: src/patterns/ffi/wrappers.md:64 src/anti_patterns/deny-warnings.md:16 #: src/anti_patterns/deref.md:69 src/functional/generics-type-classes.md:209 msgid "Advantages" -msgstr "" +msgstr "利点" #: src/idioms/concat-format.md:27 msgid "" "Using `format!` is usually the most succinct and readable way to combine " "strings." msgstr "" +"`format!` を使う方法は、通常、最も簡潔かつ読みやすい文字列結合の手段です。" #: src/idioms/concat-format.md:30 src/idioms/deref.md:50 #: src/idioms/dtor-finally.md:51 src/idioms/mem-replace.md:95 @@ -739,7 +748,7 @@ msgstr "" #: src/patterns/ffi/wrappers.md:70 src/anti_patterns/deref.md:81 #: src/functional/generics-type-classes.md:220 msgid "Disadvantages" -msgstr "" +msgstr "欠点" #: src/idioms/concat-format.md:32 msgid "" @@ -747,6 +756,9 @@ msgid "" "`push` operations on a mutable string is usually the most efficient " "(especially if the string has been pre-allocated to the expected size)." msgstr "" +"最も効率的な方法ではないことが多いです。可変な文字列に対して、`push` を繰り返" +"す方法の方が、通常は高速に処理できます(特に、文字列にあらかじめ期待されるサ" +"イズが割り当てられている場合)。" #: src/idioms/ctor.md:1 #, fuzzy From 582663ad863ef3e106177ac084e991a3999c1540 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Tue, 20 May 2025 00:46:43 +0900 Subject: [PATCH 05/12] Japanese translation: Constructors, The Default Trait --- po/ja.po | 97 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/po/ja.po b/po/ja.po index 80187b60..1860c23d 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-19 08:50+0900\n" +"PO-Revision-Date: 2025-05-20 00:46+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -761,7 +761,6 @@ msgstr "" "イズが割り当てられている場合)。" #: src/idioms/ctor.md:1 -#, fuzzy msgid "Constructors" msgstr "コンストラクタ" @@ -772,6 +771,10 @@ msgid "" "stable/book/ch05-03-method-syntax.html#associated-functions) `new` to create " "an object:" msgstr "" +"Rust には、他の言語にあるような言語仕様としてのコンストラクタは存在しません。" +"その代わりに、[関連関数](https://doc.rust-lang.org/stable/book/ch05-03-" +"method-syntax.html#associated-functions) `new` を使ってインスタンスを生成する" +"のが慣習です:" #: src/idioms/ctor.md:10 msgid "" @@ -784,27 +787,39 @@ msgid "" "/// assert_eq!(42, s.value());\n" "/// ```\n" msgstr "" +"/// 秒数を表す型。\n" +"///\n" +"/// # 使用例\n" +"///\n" +"/// ```\n" +"/// let s = Second::new(42);\n" +"/// assert_eq!(42, s.value());\n" +"/// ```\n" #: src/idioms/ctor.md:23 msgid "" "// Constructs a new instance of [`Second`].\n" " // Note this is an associated function - no self.\n" msgstr "" +"/// [`Second`] の新しいインスタンスを生成します。\n" +" /// これは関連関数であり、`self` を受け取りません。\n" #: src/idioms/ctor.md:29 src/idioms/ctor.md:54 src/idioms/ctor.md:85 msgid "/// Returns the value in seconds.\n" -msgstr "" +msgstr "/// 秒数の値を返します。\n" #: src/idioms/ctor.md:36 -#, fuzzy msgid "Default Constructors" -msgstr "コンストラクタ" +msgstr "デフォルトコンストラクタ" #: src/idioms/ctor.md:38 msgid "" "Rust supports default constructors with the [`Default`](https://doc.rust-" "lang.org/stable/std/default/trait.Default.html) trait:" msgstr "" +"Rust では、[`Default`](https://doc.rust-lang.org/stable/std/default/" +"trait.Default.html) トレイトを使うことで、デフォルトコンストラクタを定義でき" +"ます:" #: src/idioms/ctor.md:41 src/idioms/ctor.md:71 msgid "" @@ -817,12 +832,22 @@ msgid "" "/// assert_eq!(0, s.value());\n" "/// ```\n" msgstr "" +"/// 秒数を表す型。\n" +"///\n" +"/// # 使用例\n" +"///\n" +"/// ```\n" +"/// let s = Second::default();\n" +"/// assert_eq!(0, s.value());\n" +"/// ```\n" #: src/idioms/ctor.md:67 msgid "" "`Default` can also be derived if all types of all fields implement " "`Default`, like they do with `Second`:" msgstr "" +"すべてのフィールドの型が `Default` を実装している場合は、`Second` のように " +"derive できます:" #: src/idioms/ctor.md:92 msgid "" @@ -832,6 +857,10 @@ msgid "" "constructor to take no arguments, then it should, even if it is functionally " "identical to default." msgstr "" +"**補足:** Rust では、 `Default` と引数なしの `new` を両方実装するのが一般的で" +"す。`new` は Rust におけるコンストラクタの慣習であり、ユーザーも存在を期待す" +"るため、もし引数なしで構築できるために default と同じ内容になるとしても、 " +"`new` を定義すべきです。" #: src/idioms/ctor.md:97 msgid "" @@ -840,18 +869,26 @@ msgid "" "prominently, any of the [`*or_default` functions in the standard library]" "(https://doc.rust-lang.org/stable/std/?search=or_default)." msgstr "" +"**ヒント:** `Default` を実装または derive する利点は、 `Default` の実装が必要" +"とされる場所であなたの型を使えるようになることです。特に顕著なのは、[標準ライ" +"ブラリ内の `*_or_default` 関数群](https://doc.rust-lang.org/stable/std/?" +"search=or_default)です。" #: src/idioms/ctor.md:103 msgid "" "The [default idiom](default.md) for a more in-depth description of the " "`Default` trait." msgstr "" +"[Defaultトレイトの活用](default.md) でDefault トレイトについて、より詳しく説" +"明しています。" #: src/idioms/ctor.md:106 msgid "" "The [builder pattern](../patterns/creational/builder.md) for constructing " "objects where there are multiple configurations." msgstr "" +"[Builder](../patterns/creational/builder.md) は、様々な構成オプションを持つオ" +"ブジェクトを構築する際に使える設計手法です。" #: src/idioms/ctor.md:109 msgid "" @@ -859,11 +896,13 @@ msgid "" "interoperability.html#types-eagerly-implement-common-traits-c-common-traits) " "for implementing both, `Default` and `new`." msgstr "" +"[API Guidelines/C-COMMON-TRAITS](https://rust-lang.github.io/api-guidelines/" +"interoperability.html#types-eagerly-implement-common-traits-c-common-traits) " +"では、Default と new の両方を実装しています。" #: src/idioms/default.md:1 -#, fuzzy msgid "The `Default` Trait" -msgstr "Defaultトレイトの活用" +msgstr "`Default` トレイトの活用" #: src/idioms/default.md:5 msgid "" @@ -876,6 +915,14 @@ msgid "" "enum.Option.html#method.unwrap_or_default)). Notably, some containers " "already implement it where applicable." msgstr "" +"Rust の多くの型には[コンストラクタ](ctor.md)がありますが、これはそれぞれの型 " +"_固有_ のものです。Rust では「`new()` メソッドを持つすべての型」というような" +"抽象化はできません。そのために導入されたのが [`Default`](https://doc.rust-" +"lang.org/stable/std/default/trait.Default.html) トレイトです。これは、ジェネ" +"リック型やコンテナ型と組み合わせて使えるよう設計されています(例:" +"[`Option::unwrap_or_default()`](https://doc.rust-lang.org/stable/std/option/" +"enum.Option.html#method.unwrap_or_default))。なお、コンテナの中には、適用可" +"能な場合にすでに `Default` を実装しているものもあります。" #: src/idioms/default.md:11 msgid "" @@ -884,6 +931,11 @@ msgid "" "`#[derive(Default)]` for structs whose fields all implement it, so the more " "types implement `Default`, the more useful it becomes." msgstr "" +"たとえば、内部の型が `Default` を実装している `Cow`、`Box`、`Arc` などの1要素" +"コンテナ型は、`Default` を実装しています。また、構造体のすべてのフィールドが " +"`Default` を実装していれば、`#[derive(Default)]` が使えます。このように、" +"`Default` を実装する型が増えれば増えるほど、その恩恵を受けられる場面も広がり" +"ます。" #: src/idioms/default.md:16 msgid "" @@ -891,72 +943,81 @@ msgid "" "`default()` method does not. There can even be multiple constructors with " "different names, but there can only be one `Default` implementation per type." msgstr "" +"一方で、コンストラクタは複数の引数を取ることができますが、`default()` メソッ" +"ドはそうではありません。また、複数の異なる名前のコンストラクタを定義すること" +"は可能ですが、`Default` トレイトの実装は型ごとに1つだけです。" #: src/idioms/default.md:24 msgid "// note that we can simply auto-derive Default here.\n" -msgstr "" +msgstr "// Default を derive して自動実装できる\n" #: src/idioms/default.md:28 msgid "// Option defaults to None\n" -msgstr "" +msgstr "// Option はデフォルトで None\n" #: src/idioms/default.md:30 msgid "// Vecs default to empty vector\n" -msgstr "" +msgstr "// Vec は空のベクタがデフォルト\n" #: src/idioms/default.md:32 msgid "// Duration defaults to zero time\n" -msgstr "" +msgstr "// Duration はゼロ時間がデフォルト\n" #: src/idioms/default.md:34 msgid "// bool defaults to false\n" -msgstr "" +msgstr "// bool は false がデフォルト\n" #: src/idioms/default.md:39 msgid "// add setters here\n" -msgstr "" +msgstr "// セッターなどをここに追加できる\n" #: src/idioms/default.md:43 msgid "// construct a new instance with default values\n" -msgstr "" +msgstr "// デフォルト値でインスタンスを生成\n" #: src/idioms/default.md:45 msgid "// do something with conf here\n" -msgstr "" +msgstr "// conf に対して何らか処理を行う\n" #: src/idioms/default.md:47 msgid "\"conf = {conf:#?}\"" -msgstr "" +msgstr "\"conf = {conf:#?}\"" #: src/idioms/default.md:49 msgid "" "// partial initialization with default values, creates the same instance\n" msgstr "" +"// 部分的にデフォルト値を使った初期化。結果は上のインスタンスと同じになる\n" #: src/idioms/default.md:60 msgid "" "The [constructor](ctor.md) idiom is another way to generate instances that " "may or may not be \"default\"" msgstr "" +"[コンストラクタ](ctor.md)は、デフォルト値ではないインスタンスを生成する別の手" +"法です。" #: src/idioms/default.md:62 msgid "" "The [`Default`](https://doc.rust-lang.org/stable/std/default/" "trait.Default.html) documentation (scroll down for the list of implementors)" msgstr "" +"[`Default`](https://doc.rust-lang.org/stable/std/default/trait.Default.html) " +"トレイトのドキュメント(スクロールすると実装例の一覧があります)。" #: src/idioms/default.md:63 msgid "" "[`Option::unwrap_or_default()`](https://doc.rust-lang.org/stable/std/option/" "enum.Option.html#method.unwrap_or_default)" msgstr "" +"[`Option::unwrap_or_default()`](https://doc.rust-lang.org/stable/std/option/" +"enum.Option.html#method.unwrap_or_default)" #: src/idioms/default.md:64 msgid "[`derive(new)`](https://crates.io/crates/derive-new/)" -msgstr "" +msgstr "[`derive(new)`](https://crates.io/crates/derive-new/)" #: src/idioms/deref.md:1 -#, fuzzy msgid "Collections are smart pointers" msgstr "コレクションはスマートポインタである" From 32152923f6ed432906c7d271499d9b644550eca0 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Tue, 20 May 2025 19:12:43 +0900 Subject: [PATCH 06/12] Japanese translation: Collections are smart pointers --- po/ja.po | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/po/ja.po b/po/ja.po index 1860c23d..6da08432 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-20 00:46+0900\n" +"PO-Revision-Date: 2025-05-20 19:11+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -182,7 +182,7 @@ msgstr "" #: src/SUMMARY.md:47 msgid "Deref Polymorphism" -msgstr "" +msgstr "Deref による多態性" #: src/SUMMARY.md:49 msgid "Functional Programming" @@ -1027,12 +1027,15 @@ msgid "" "to treat collections like smart pointers, offering owning and borrowed views " "of data." msgstr "" +"[`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) トレイトを使う" +"ことで、コレクションをスマートポインタのように扱い、所有ビューと借用ビューの" +"両方を提供できます。" #: src/idioms/deref.md:16 src/idioms/deref.md:23 #: src/patterns/behavioural/RAII.md:29 src/patterns/behavioural/RAII.md:41 #: src/patterns/behavioural/RAII.md:100 src/anti_patterns/deref.md:35 msgid "//..\n" -msgstr "" +msgstr "//..\n" #: src/idioms/deref.md:28 msgid "" @@ -1042,10 +1045,15 @@ msgid "" "dereferencing searches. Most methods you might expect to be implemented for " "`Vec`s are instead implemented for slices." msgstr "" +"`Vec` は `T` の所有コレクションであり、一方スライス(`&[T]`)は `T` の借用" +"コレクションです。`Vec` に対して `Deref` を実装することで、`&Vec` から " +"`&[T]` への暗黙的なデリファレンスが可能になり、この関係性は自動デリファレンス" +"の探索にも含まれるようになります。`Vec` に実装されているように見える多くのメ" +"ソッドは、実際にはスライスに対して実装されています。" #: src/idioms/deref.md:34 msgid "Also `String` and `&str` have a similar relation." -msgstr "" +msgstr "`String` と `&str` の関係もこれと同様です。" #: src/idioms/deref.md:36 src/idioms/dtor-finally.md:36 #: src/idioms/mem-replace.md:63 src/idioms/on-stack-dyn-dispatch.md:32 @@ -1060,7 +1068,7 @@ msgstr "" #: src/patterns/structural/compose-structs.md:100 src/patterns/ffi/export.md:16 #: src/anti_patterns/borrow_clone.md:30 msgid "Motivation" -msgstr "" +msgstr "動機" #: src/idioms/deref.md:38 msgid "" @@ -1069,16 +1077,23 @@ msgid "" "experience. When implementing a data structure that owns its data, offering " "a borrowed view of that data allows for more flexible APIs." msgstr "" +"所有権と借用は、Rust における主要な言語機能です。良い開発体験のために、データ" +"構造を設計する際にはこれらのセマンティクスを適切に考慮する必要があります。所" +"有データを持つ構造体に借用ビューを提供することで、より柔軟な API を実現できま" +"す。" #: src/idioms/deref.md:45 msgid "" "Most methods can be implemented only for the borrowed view, they are then " "implicitly available for the owning view." msgstr "" +"多くのメソッドは借用ビューに対してのみ実装すればよく、所有ビューでも暗黙的に" +"使用できます。" #: src/idioms/deref.md:48 msgid "Gives clients a choice between borrowing or taking ownership of data." msgstr "" +"使用する際に、データの借用と所有権の取得のどちらかを選ぶことができます。" #: src/idioms/deref.md:52 msgid "" @@ -1087,6 +1102,10 @@ msgid "" "using this pattern can get complex (see the `Borrow` and `AsRef` traits, " "etc.)." msgstr "" +"デリファレンスを通じてのみ利用できるメソッドやトレイトは、境界条件のチェック" +"において考慮されません。そのため、このパターンを用いたデータ構造では、ジェネ" +"リックプログラミングが複雑になる可能性があります(`Borrow` や `AsRef` トレイ" +"トなどを参照)。" #: src/idioms/deref.md:56 src/idioms/dtor-finally.md:66 #: src/idioms/mem-replace.md:105 src/idioms/on-stack-dyn-dispatch.md:66 @@ -1100,7 +1119,7 @@ msgstr "" #: src/patterns/structural/compose-structs.md:117 #: src/anti_patterns/deref.md:102 msgid "Discussion" -msgstr "" +msgstr "議論" #: src/idioms/deref.md:58 msgid "" @@ -1113,6 +1132,13 @@ msgid "" "If a collection owns its data, it is usually useful to provide a view of the " "data as borrowed so that it can be referenced multiple times." msgstr "" +"スマートポインタとコレクションは類似しています:スマートポインタは1つの値を指" +"し、コレクションは複数の値を指します。型システムの観点から見れば、この2つに大" +"きな違いはありません。あるコレクションがそのデータへの唯一のアクセス手段であ" +"り、かつそのコレクションがデータの破棄責任を持っているならば(たとえ共有所有" +"であっても)、そのコレクションはデータを所有していると言えます。そして、所有" +"している場合は通常、借用ビューを提供することが有用です。それにより、同じデー" +"タを複数箇所から参照できるようになります。" #: src/idioms/deref.md:67 msgid "" @@ -1122,25 +1148,34 @@ msgid "" "`Foo` can implement `Deref>` where `Bar` is a dynamically " "sized type and `&Bar` is a borrowed view of the data in `Foo`." msgstr "" +"スマートポインタの多く(たとえば `Foo`)は、`Deref` を実装して" +"います。一方、コレクションは通常、カスタム型にデリファレンスします。`[T]` や " +"`str` のような型は言語レベルのサポートを受けていますが、一般的にはこれは必須" +"ではありません。たとえば、`Foo` が `Deref>` を実装すること" +"も可能であり、ここで `Bar` は動的サイズ型で、`&Bar` は `Foo` に格納され" +"たデータの借用ビューになります。" #: src/idioms/deref.md:73 msgid "" "Commonly, ordered collections will implement `Index` for `Range`s to provide " "slicing syntax. The target will be the borrowed view." msgstr "" +"一般的に、順序付きコレクションは `Index` を `Range` に対して実装することで、" +"スライス構文をサポートします。このとき、ターゲットは借用ビューになります。" #: src/idioms/deref.md:78 msgid "[Deref polymorphism anti-pattern](../anti_patterns/deref.md)." -msgstr "" +msgstr "[Deref による多態性のアンチパターン](../anti_patterns/deref.md)。" #: src/idioms/deref.md:79 src/anti_patterns/deref.md:130 msgid "" "[Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/" "trait.Deref.html)." msgstr "" +"[`Deref` トレイトのドキュメント](https://doc.rust-lang.org/std/ops/" +"trait.Deref.html)。" #: src/idioms/dtor-finally.md:1 -#, fuzzy msgid "Finalisation in destructors" msgstr "デストラクタでの後処理" From db90794240d54dc4d09452364e7392ebe61ae99e Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Tue, 20 May 2025 20:06:38 +0900 Subject: [PATCH 07/12] Japanese translation: Finalisation in destructors --- po/ja.po | 59 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/po/ja.po b/po/ja.po index 6da08432..15a0b1ca 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-20 19:11+0900\n" +"PO-Revision-Date: 2025-05-20 20:03+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -122,7 +122,7 @@ msgstr "" #: src/SUMMARY.md:30 msgid "RAII Guards" -msgstr "" +msgstr "RAIIガード" #: src/SUMMARY.md:31 msgid "Strategy" @@ -1185,34 +1185,37 @@ msgid "" "executed no matter how a function is exited. Instead, an object's destructor " "can be used to run code that must be run before exit." msgstr "" +"Rust には、関数の終了方法にかかわらず常に実行されるコード(finally ブロックの" +"ような構文)は存在しません。その代わりに、オブジェクトのデストラクタを使っ" +"て、終了前に必ず実行したい処理を行うことができます。" #: src/idioms/dtor-finally.md:13 msgid "// some code\n" -msgstr "" +msgstr "// 何らかの処理\n" #: src/idioms/dtor-finally.md:17 msgid "// These don't need to be defined inside the function.\n" -msgstr "" +msgstr "// 以下の型定義は関数内でなくてもよい。\n" #: src/idioms/dtor-finally.md:20 msgid "// Implement a destructor for Foo.\n" -msgstr "" +msgstr "// Foo に対してデストラクタを実装\n" #: src/idioms/dtor-finally.md:23 msgid "\"exit\"" -msgstr "" +msgstr "\"exit\"" #: src/idioms/dtor-finally.md:27 msgid "// The dtor of _exit will run however the function `bar` is exited.\n" -msgstr "" +msgstr "// `bar` 関数がどのように終了しても、_exit のデストラクタは呼ばれる\n" #: src/idioms/dtor-finally.md:29 msgid "// Implicit return with `?` operator.\n" -msgstr "" +msgstr "// `?` 演算子による暗黙の return\n" #: src/idioms/dtor-finally.md:31 msgid "// Normal return.\n" -msgstr "" +msgstr "// 通常の return\n" #: src/idioms/dtor-finally.md:38 msgid "" @@ -1224,12 +1227,20 @@ msgid "" "has `finally`), there is no way to schedule code to run in both the normal " "and exceptional cases. Panicking will also exit a function early." msgstr "" +"関数に複数の return パスがある場合、関数終了時に処理を行うのは困難かつ冗長に" +"なりがちで、結果としてバグの温床にもなります。特にマクロなどにより return が" +"暗黙的になる場合はさらに顕著です。典型的なのが `?` 演算子です。これは結果が " +"`Err` の場合に即 return し、`Ok` の場合のみ処理を続けます。例外処理的に使え" +"る `?` ですが、`finally` ブロックを持つJavaのような言語と違い、Rust には通常" +"と異常の両方のケースで実行されるコードを明示的に書く方法がないのです。また、" +"panic が発生した場合も関数は早期に終了します。" #: src/idioms/dtor-finally.md:48 msgid "" "Code in destructors will (nearly) always be run - copes with panics, early " "returns, etc." msgstr "" +"デストラクタ内のコードは、panic や早期 return を含めてほぼ常に実行される。" #: src/idioms/dtor-finally.md:53 msgid "" @@ -1239,6 +1250,10 @@ msgid "" "thread. Therefore, destructors cannot be relied on as finalizers where it is " "absolutely essential that finalisation happens." msgstr "" +"デストラクタが確実に実行される保証はありません。たとえば、無限ループがある関" +"数や、処理中にクラッシュした場合などです。また、すでに panic 中のスレッド内で" +"さらに panic が発生した場合、デストラクタは実行されません。したがって、絶対に" +"後処理が必要な場面でデストラクタに頼るのは危険です。" #: src/idioms/dtor-finally.md:59 msgid "" @@ -1246,12 +1261,16 @@ msgid "" "function gives no clear indication of destructors to be run on exit. This " "can make debugging tricky." msgstr "" +"このパターンは、気付きにくい暗黙のコードを含みます。関数を読んだだけでは後処" +"理コードが見えないため、コードの可読性・デバッグ性を損なう可能性があります。" #: src/idioms/dtor-finally.md:63 msgid "" "Requiring an object and `Drop` impl just for finalisation is heavy on " "boilerplate." msgstr "" +"後処理のためだけに構造体と `Drop` 実装を用意するのは、定型コードが多くなりま" +"す。" #: src/idioms/dtor-finally.md:68 msgid "" @@ -1262,6 +1281,13 @@ msgid "" "finalizer can be kept alive beyond the lifetime of the function. For similar " "reasons, the finalizer should not be moved or returned." msgstr "" +"後処理用のオブジェクトをどのように保持するかには注意が必要です。このオブジェ" +"クトは関数の終了まで生存していなければならず、終了時に破棄される必要がありま" +"す。このため、値として(または `Box` のような一意な所有ポインタとして)" +"保持しなければなりません。`Rc` のような共有ポインタを使うと、スコープの外でも" +"オブジェクトが生き残ってしまい、関数の終了と同時に破棄される保証がなくなりま" +"す。また、後処理用オブジェクトは関数から move したり返したりしてはいけませ" +"ん。" #: src/idioms/dtor-finally.md:75 msgid "" @@ -1272,6 +1298,10 @@ msgid "" "do not call the variable `_` with no suffix - in that case it will be " "destroyed immediately." msgstr "" +"もう一点重要なのは、後処理用オブジェクトは変数に束縛しなければならないという" +"点です。そうしないと、すぐに破棄されてしまい、関数終了時まで生き残りません。" +"もし変数が使われない目的で定義されるのであれば、 `_` で始めるべきです。ただ" +"し、変数名をただの `_` にすると、即座に破棄されてしまうので注意が必要です。" #: src/idioms/dtor-finally.md:81 msgid "" @@ -1281,6 +1311,11 @@ msgid "" "object in each stack frame. So, destructors get called even if the panic " "happens in a function being called." msgstr "" +"Rust においてデストラクタはスコープを抜けたときに実行されます。これは、ブロッ" +"クの末尾に到達したとき、早期 return、または panic のいずれでも同様です。" +"panic 時には Rust はスタックを巻き戻しながら、各スタックフレーム内のオブジェ" +"クトのデストラクタを呼び出します。つまり、呼び出し中の関数で panic が発生して" +"も、デストラクタは実行されます。" #: src/idioms/dtor-finally.md:87 msgid "" @@ -1290,10 +1325,14 @@ msgid "" "means that you must take extra care in your destructors not to panic, since " "it could leave resources in an unexpected state." msgstr "" +"しかし、スタック巻き戻し中にデストラクタ内で再度 panic が発生した場合、Rust " +"は安全のためスレッドを即時中断(abort)し、それ以降のデストラクタは実行されま" +"せん。そのため、デストラクタ内での panic は避けるべきです。そうでないと、リ" +"ソースが適切に解放されず、予期せぬ状態が残る可能性があります。" #: src/idioms/dtor-finally.md:95 msgid "[RAII guards](../patterns/behavioural/RAII.md)." -msgstr "" +msgstr "[RAIIガード](../patterns/behavioural/RAII.md)。" #: src/idioms/mem-replace.md:1 msgid "`mem::{take(_), replace(_)}` to keep owned values in changed enums" From e0f45470ad0026aaeb102cac50590bd273068290 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Tue, 20 May 2025 21:39:20 +0900 Subject: [PATCH 08/12] Japanese translation: mem::{take(_), replace(_)} --- po/ja.po | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/po/ja.po b/po/ja.po index 15a0b1ca..f19f9306 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-20 20:03+0900\n" +"PO-Revision-Date: 2025-05-20 21:38+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -174,7 +174,7 @@ msgstr "" #: src/SUMMARY.md:45 src/anti_patterns/borrow_clone.md:1 msgid "Clone to satisfy the borrow checker" -msgstr "" +msgstr "借用チェッカーを満足させるためのクローン" #: src/SUMMARY.md:46 msgid "`#[deny(warnings)]`" @@ -1336,7 +1336,7 @@ msgstr "[RAIIガード](../patterns/behavioural/RAII.md)。" #: src/idioms/mem-replace.md:1 msgid "`mem::{take(_), replace(_)}` to keep owned values in changed enums" -msgstr "" +msgstr "`mem::{take(_), replace(_)}` を使って列挙型の所有値を保持する" #: src/idioms/mem-replace.md:5 msgid "" @@ -1344,10 +1344,14 @@ msgid "" "String, x: u8 }` and `B { name: String }`. Now we want to change `MyEnum::A` " "to a `B` if `x` is zero, while keeping `MyEnum::B` intact." msgstr "" +"`A { name: String, x: u8 }` と `B { name: String }` という(少なくとも)2つの" +"バリアントを持つ `&mut MyEnum`があるします。ここで、`x` が 0 の場合に " +"`MyEnum::A` から `B` に変更したいが、B はそのままにしたい、という状況を考えま" +"す。" #: src/idioms/mem-replace.md:9 msgid "We can do this without cloning the `name`." -msgstr "" +msgstr "この変換は、`name` をクローンせずに行うことができます。" #: src/idioms/mem-replace.md:23 msgid "" @@ -1356,16 +1360,21 @@ msgid "" " // Then, construct the new enum variant (which will\n" " // be assigned to `*e`).\n" msgstr "" +"// `name` を取り出し、代わりに空の String を挿入する。\n" +" // (空の文字列はヒープ割り当てを伴わない点に注意)\n" +" // 新しいバリアントを作って、`*e` に代入する。\n" #: src/idioms/mem-replace.md:34 msgid "This also works with more variants:" -msgstr "" +msgstr "この手法は、複数のバリアントを持つ列挙型にも使えます:" #: src/idioms/mem-replace.md:49 msgid "" "// Ownership rules do not allow taking `name` by value, but we cannot\n" " // take the value out of a mutable reference, unless we replace it:\n" msgstr "" +"// 所有権ルールにより、name を値として取り出すことはできないが、\n" +" // mutable な参照から値を取り出すには何かで置き換える必要がある。\n" #: src/idioms/mem-replace.md:65 msgid "" @@ -1375,6 +1384,9 @@ msgid "" "look at its parts to decide what to do next. In the second phase we may " "conditionally change the value (as in the example above)." msgstr "" +"列挙型を扱うとき、その場で別のバリアントに切り替えたい場合があります。こうし" +"た変更は、通常2段階に分けて行います。まず現在の値を観察して、次に何をすべきか" +"を判断します。そして、条件に応じてバリアントを変更します。(上の例のように)" #: src/idioms/mem-replace.md:71 msgid "" @@ -1385,6 +1397,12 @@ msgid "" "Anyway, we can avoid the extra allocation by changing `e` with only a " "mutable borrow." msgstr "" +"所有権ルールにより、列挙型から `name` を「そのまま取り出す」ことはできません" +"( _何かしら_ 中に残っている必要があるためです)。name を `.clone()` して " +"`MyEnum::B` に入れる方法もありますが、それは借用チェッカーに合わせるための " +"[借用チェッカーを満足させるためのクローン](../anti_patterns/borrow_clone.md)" +"に該当します。ですが、`e` を可変参照のまま変更することで、余分なメモリ割り当" +"てを回避できます。" #: src/idioms/mem-replace.md:78 msgid "" @@ -1393,6 +1411,10 @@ msgid "" "empty `String`, which does not need to allocate. As a result, we get the " "original `name` _as an owned value_. We can then wrap this in another enum." msgstr "" +"`mem::take` は、値を取り出して、代わりにその型のデフォルト値を挿入します。そ" +"して取り出した値を返す関数です。`String` のデフォルト値は空の文字列で、これは" +"ヒープ割り当てを伴いません。そのため、`name` を _所有された値_ として取得し、" +"それを別のバリアントに包むことができます。" #: src/idioms/mem-replace.md:83 msgid "" @@ -1400,6 +1422,9 @@ msgid "" "replace the value with. An equivalent to our `mem::take` line would be " "`mem::replace(name, String::new())`." msgstr "" +"**補足:** `mem::replace` は `mem::take` と非常に似ていますが、代わりに入れる" +"値を明示的に指定できる点が異なります。たとえば `mem::take(name)` と同じ意味を" +"持つコードは、`mem::replace(name, String::new())` です。" #: src/idioms/mem-replace.md:87 msgid "" @@ -1407,11 +1432,16 @@ msgid "" "value with a `None`, `Option`’s `take()` method provides a shorter and more " "idiomatic alternative." msgstr "" +"対象が `Option` の場合で `None` に置き換えたいときは、`Option` の `take()` メ" +"ソッドを使った方がより簡潔で慣用的です。" #: src/idioms/mem-replace.md:93 msgid "" "Look ma, no allocation! Also you may feel like Indiana Jones while doing it." msgstr "" +"メモリ割り当てなしで所有値を移動できる!そして何より、インディ・ジョーンズ感" +"を味わえるかも。(訳注:インディ・ジョーンズが宝を台座から盗るとき、重さを変" +"えずに罠を作動させないために砂袋と交換する場面)" #: src/idioms/mem-replace.md:97 msgid "" @@ -1420,6 +1450,9 @@ msgid "" "resulting in reduced performance as opposed to what you'd do in unsafe " "languages." msgstr "" +"コードがやや冗長になりがちです。何度かミスすると、借用チェッカーに嫌気が差す" +"可能性があります。コンパイラが二重書き換えを最適化できず、パフォーマンスが落" +"ちる可能性もあります(unsafe な言語であれば回避可能な場面も)。" #: src/idioms/mem-replace.md:101 msgid "" @@ -1427,6 +1460,9 @@ msgid "" "(./default.md). However, if the type you're working with doesn't implement " "this, you can instead use `mem::replace`." msgstr "" +"また、このパターンでは対象の型が [`Default` トレイト](./default.md) を実装し" +"ている必要があります。もし対象の型が `Default` を実装していない場合は、代わり" +"に `mem::replace` を使えます。" #: src/idioms/mem-replace.md:107 msgid "" @@ -1435,6 +1471,9 @@ msgid "" "in other low-level languages like C you'd simply alias the pointer and fix " "things later." msgstr "" +"このパターンが重要になるのは Rust に限った話です。GC を持つ言語では、値への参" +"照をそのまま使えばよく、GC が参照の追跡を行ってくれます。C のような低レベル言" +"語では、ポインタをエイリアスし、後で修正します。" #: src/idioms/mem-replace.md:112 msgid "" @@ -1442,12 +1481,17 @@ msgid "" "value may only have one owner, so to take it out, we need to put something " "back in – like Indiana Jones, replacing the artifact with a bag of sand." msgstr "" +"しかし Rust では、所有値は1人の所有者しか持てないため、値を取り出すには、代わ" +"りに何かを入れておく必要があるのです。まるでインディ・ジョーンズが遺物を砂袋" +"に置き換えるようなイメージですね。" #: src/idioms/mem-replace.md:118 msgid "" "This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/" "borrow_clone.md) anti-pattern in a specific case." msgstr "" +"これは、[借用チェッカーを満足させるためのクローン](../anti_patterns/" +"borrow_clone.md)アンチパターンを特定の状況で回避するために使えます。" #: src/idioms/on-stack-dyn-dispatch.md:5 msgid "" From a3ff3632cd0366eadec17d4151ecb7a4247e7b49 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Wed, 21 May 2025 01:02:53 +0900 Subject: [PATCH 09/12] Japanese translation: On-Stack Dynamic Dispatch --- po/ja.po | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/po/ja.po b/po/ja.po index f19f9306..b4a7676e 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-20 21:38+0900\n" +"PO-Revision-Date: 2025-05-21 01:02+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -1336,7 +1336,7 @@ msgstr "[RAIIガード](../patterns/behavioural/RAII.md)。" #: src/idioms/mem-replace.md:1 msgid "`mem::{take(_), replace(_)}` to keep owned values in changed enums" -msgstr "`mem::{take(_), replace(_)}` を使って列挙型の所有値を保持する" +msgstr "`mem::{take(_), replace(_)}` で変更するenumの所有値を保持する" #: src/idioms/mem-replace.md:5 msgid "" @@ -1500,21 +1500,24 @@ msgid "" "the lifetime as necessary, we can use deferred conditional initialization, " "as seen below:" msgstr "" +"複数の値に対して動的ディスパッチを行うことは可能ですが、異なる型のオブジェク" +"トを束縛するためには、複数の変数を定義する必要があります。必要に応じてライフ" +"タイムを延ばすには、以下のように遅延条件付き初期化を使うことができます:" #: src/idioms/on-stack-dyn-dispatch.md:17 #: src/idioms/on-stack-dyn-dispatch.md:20 #: src/idioms/on-stack-dyn-dispatch.md:56 msgid "\"-\"" -msgstr "" +msgstr "\"-\"" #: src/idioms/on-stack-dyn-dispatch.md:18 msgid "// We need to describe the type to get dynamic dispatch.\n" -msgstr "" +msgstr "// 動的ディスパッチを行うには型を明示する必要があります。\n" #: src/idioms/on-stack-dyn-dispatch.md:25 #: src/idioms/on-stack-dyn-dispatch.md:60 msgid "// Read from `readable` here.\n" -msgstr "" +msgstr "// ここで `readable` から読み込みを行う。\n" #: src/idioms/on-stack-dyn-dispatch.md:34 msgid "" @@ -1524,12 +1527,18 @@ msgid "" "places where performance is not of the essence, thus costing compile time " "and cache usage." msgstr "" +"Rust はデフォルトでコードを単一型に展開します。つまり、ジェネリクスなどで使わ" +"れた型ごとに個別のコードが生成され、それぞれ最適化されます。これはホットパス" +"での高速化には非常に有効ですが、パフォーマンスが重要でない場面ではコードの肥" +"大化を招き、コンパイル時間やキャッシュ使用量の増大といった副作用があります。" #: src/idioms/on-stack-dyn-dispatch.md:40 msgid "" "Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " "ask for it." msgstr "" +"幸い、Rust では動的ディスパッチを使用することも可能ですが、明示的に指定する必" +"要があります。" #: src/idioms/on-stack-dyn-dispatch.md:45 msgid "" @@ -1537,6 +1546,9 @@ msgid "" "initialize something we won't use later, nor do we need to monomorphize the " "whole code that follows to work with both `File` or `Stdin`." msgstr "" +"ヒープ上に何も割り当てる必要がありません。後で使わないかもしれない値を事前に" +"初期化する必要もありません。`File` と `Stdin` の両方に対応するために、後続" +"コード全体を単一型展開する必要もありません。" #: src/idioms/on-stack-dyn-dispatch.md:51 msgid "" @@ -1544,14 +1556,17 @@ msgid "" "initialization, which made up more moving parts than the `Box`\\-based " "version:" msgstr "" +"Rust 1.79.0 より前のバージョンでは、遅延初期化のために `let` バインディングを" +"2段階で書く必要があり、`Box` を使ったバージョンよりもコードの構造が煩雑でし" +"た:" #: src/idioms/on-stack-dyn-dispatch.md:55 msgid "// We still need to ascribe the type for dynamic dispatch.\n" -msgstr "" +msgstr "// 動的ディスパッチのために型注釈が依然として必要です。\n" #: src/idioms/on-stack-dyn-dispatch.md:64 msgid "Luckily, this disadvantage is now gone. Yay!" -msgstr "" +msgstr "とはいえ、この制約は現在では解消されています。やったね!" #: src/idioms/on-stack-dyn-dispatch.md:68 msgid "" @@ -1559,6 +1574,8 @@ msgid "" "temporary values within `&` or `&mut` as long as possible within the scope " "of the function." msgstr "" +"Rust 1.79.0 以降では、`&` や `&mut` による一時値のライフタイムを、関数スコー" +"プ内で可能な限り延長するように、コンパイラが自動的に処理してくれます。" #: src/idioms/on-stack-dyn-dispatch.md:72 msgid "" @@ -1566,6 +1583,8 @@ msgid "" "placing the contents into some `let` binding (which would have been needed " "for deferred initialization, which was the solution used before that change)." msgstr "" +"そのため、値を `let` バインディングに明示的に束縛しなくても、単に `&mut` を使" +"えばよくなりました(以前のような遅延初期化パターンは不要になります)。" #: src/idioms/on-stack-dyn-dispatch.md:76 msgid "" @@ -1573,12 +1592,17 @@ msgid "" "compiler knows the size of each value and each borrowed value outlives all " "references borrowed from it." msgstr "" +"各値には一時的にせよ居場所が確保されており、コンパイラはそのサイズを把握して" +"いて、かつ借用された参照がすべて元の値のライフタイム内にあることを理解してい" +"ます。" #: src/idioms/on-stack-dyn-dispatch.md:82 msgid "" "[Finalisation in destructors](dtor-finally.md) and [RAII guards](../patterns/" "behavioural/RAII.md) can benefit from tight control over lifetimes." msgstr "" +"[デストラクタでの後処理](dtor-finally.md)と[RAII ガード](../patterns/" +"behavioural/RAII.md)は、ライフタイム制御の活用例として有益です。" #: src/idioms/on-stack-dyn-dispatch.md:85 msgid "" @@ -1587,6 +1611,10 @@ msgid "" "doc.rust-lang.org/std/option/enum.Option.html#method.as_ref) method to get " "an optional reference." msgstr "" +"可変な参照の条件付き `Option<&T>` を使いたい場合は、`Option` を直接初期化" +"して、[`as_ref()`](https://doc.rust-lang.org/std/option/" +"enum.Option.html#method.as_ref) メソッド を使うことで、Optionの参照が得られま" +"す。" #: src/idioms/ffi/intro.md:1 #, fuzzy From da9b7a73a30e6b3a087618fbf15cad0115cb8e48 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Fri, 23 May 2025 00:11:01 +0900 Subject: [PATCH 10/12] Japanese translation: FFI Idioms, Error Handling in FFI --- po/ja.po | 68 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/po/ja.po b/po/ja.po index b4a7676e..9f38a0e5 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-21 01:02+0900\n" +"PO-Revision-Date: 2025-05-23 00:10+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -66,11 +66,11 @@ msgstr "外部関数インターフェース(FFI)" #: src/SUMMARY.md:15 msgid "Idiomatic Errors" -msgstr "FFIに適したエラー処理" +msgstr "イディオムに則ったエラー処理" #: src/SUMMARY.md:16 src/idioms/ffi/accepting-strings.md:1 msgid "Accepting Strings" -msgstr "文字列の受け取り方" +msgstr "文字列の受け入れ方" #: src/SUMMARY.md:17 src/idioms/ffi/passing-strings.md:1 msgid "Passing Strings" @@ -1433,7 +1433,7 @@ msgid "" "idiomatic alternative." msgstr "" "対象が `Option` の場合で `None` に置き換えたいときは、`Option` の `take()` メ" -"ソッドを使った方がより簡潔で慣用的です。" +"ソッドを使った方がより簡潔でイディオムに則っています。" #: src/idioms/mem-replace.md:93 msgid "" @@ -1617,9 +1617,8 @@ msgstr "" "す。" #: src/idioms/ffi/intro.md:1 -#, fuzzy msgid "FFI Idioms" -msgstr "慣習" +msgstr "FFI におけるイディオム" #: src/idioms/ffi/intro.md:3 msgid "" @@ -1627,28 +1626,36 @@ msgid "" "idioms here that can act as pointers, and avoid traps for inexperienced " "users of `unsafe` Rust." msgstr "" +"FFIコードの記述は、それ自体がひとつの講座になるほど奥が深い分野です。このセク" +"ションでは、FFI に関する 典型的な書き方をいくつか紹介します。これらは " +"`unsafe` な Rust に不慣れな方が陥りがちな罠を避けるための指針 となるはずで" +"す。" #: src/idioms/ffi/intro.md:7 msgid "This section contains idioms that may be useful when doing FFI." msgstr "" +"このセクションでは、FFI を扱う際に役立つかもしれないイディオムを紹介します。" #: src/idioms/ffi/intro.md:9 msgid "" "[Idiomatic Errors](./errors.md) - Error handling with integer codes and " "sentinel return values (such as `NULL` pointers)" msgstr "" +"整数によるエラーコードや`NULL` ポインタのような番兵値を使った、[イディオムに" +"則ったエラー処理](./errors.md)" #: src/idioms/ffi/intro.md:12 msgid "[Accepting Strings](./accepting-strings.md) with minimal unsafe code" msgstr "" +"unsafe コードを最小限に抑える[文字列の受け入れ方](./accepting-strings.md)" #: src/idioms/ffi/intro.md:14 msgid "[Passing Strings](./passing-strings.md) to FFI functions" -msgstr "" +msgstr "FFI 関数への[文字列の渡し方](./passing-strings.md)" #: src/idioms/ffi/errors.md:1 msgid "Error Handling in FFI" -msgstr "" +msgstr "FFI におけるエラー処理" #: src/idioms/ffi/errors.md:5 msgid "" @@ -1656,114 +1663,123 @@ msgid "" "However, Rust's type system allows much more rich error information to be " "captured and propagated through a full type." msgstr "" +"C のような他言語においては、エラーは通常戻り値のコードで表現されます。一方、" +"Rust の型システムでは、より豊富なエラー情報を型として安全に表現し、伝播させる" +"ことができます。" #: src/idioms/ffi/errors.md:9 msgid "" "This best practice shows different kinds of error codes, and how to expose " "them in a usable way:" msgstr "" +"この章では、異なる種類のエラーコードをどのように扱い、FFI 経由で実用的に公開" +"するかについて、ベストプラクティスを示します:" #: src/idioms/ffi/errors.md:12 msgid "Flat Enums should be converted to integers and returned as codes." -msgstr "" +msgstr "単純な列挙型は整数に変換してコードとして返す。" #: src/idioms/ffi/errors.md:13 msgid "" "Structured Enums should be converted to an integer code with a string error " "message for detail." -msgstr "" +msgstr "構造を持つ列挙型は、整数コードと併せて文字列エラーメッセージを返す。" #: src/idioms/ffi/errors.md:15 msgid "" "Custom Error Types should become \"transparent\", with a C representation." msgstr "" +"カスタムエラー型は C 向けに「透過的(transparent)」な構造体として公開する。" #: src/idioms/ffi/errors.md:17 src/idioms/ffi/accepting-strings.md:29 #: src/idioms/ffi/passing-strings.md:26 src/patterns/ffi/export.md:44 #: src/patterns/ffi/wrappers.md:24 msgid "Code Example" -msgstr "" +msgstr "コード例" #: src/idioms/ffi/errors.md:19 msgid "Flat Enums" -msgstr "" +msgstr "単純な列挙型" #: src/idioms/ffi/errors.md:23 msgid "// user attempted a write operation\n" -msgstr "" +msgstr "// 書き込み操作が試みられた\n" #: src/idioms/ffi/errors.md:24 msgid "// user should read the C errno() for what it was\n" -msgstr "" +msgstr "// 詳細は C の errno() を確認\n" #: src/idioms/ffi/errors.md:25 msgid "// user should run a repair tool to recover it\n" -msgstr "" +msgstr "// 修復ツールを使って復旧すべき\n" #: src/idioms/ffi/errors.md:35 msgid "Structured Enums" -msgstr "" +msgstr "構造を持つ列挙型" #: src/idioms/ffi/errors.md:42 msgid "// message describing the issue\n" -msgstr "" +msgstr "// 問題の説明を含む\n" #: src/idioms/ffi/errors.md:61 src/idioms/ffi/accepting-strings.md:47 #: src/idioms/ffi/accepting-strings.md:79 src/idioms/ffi/passing-strings.md:33 #: src/patterns/ffi/export.md:154 src/patterns/ffi/export.md:158 #: src/patterns/ffi/export.md:165 msgid "\"C\"" -msgstr "" +msgstr "\"C\"" #: src/idioms/ffi/errors.md:64 msgid "" "// SAFETY: we assume that the lifetime of `e` is greater than\n" " // the current stack frame.\n" -msgstr "" +msgstr "// SAFETY: `e` のライフタイムが現在のスタックフレームより長いと仮定\n" #: src/idioms/ffi/errors.md:70 msgid "\"cannot write to read-only database\"" -msgstr "" +msgstr "\"cannot write to read-only database\"" #: src/idioms/ffi/errors.md:73 msgid "\"I/O Error: {e}\"" -msgstr "" +msgstr "\"I/O Error: {e}\"" #: src/idioms/ffi/errors.md:76 msgid "\"File corrupted, run repair: {}\"" -msgstr "" +msgstr "\"File corrupted, run repair: {}\"" #: src/idioms/ffi/errors.md:83 msgid "" "// SAFETY: copying error_bytes to an allocated buffer with a '\\0'\n" " // byte at the end.\n" -msgstr "" +msgstr "// SAFETY: error_bytes を'\\0'終端付きで確保したバッファにコピー\n" #: src/idioms/ffi/errors.md:99 msgid "Custom Error Types" -msgstr "" +msgstr "カスタムエラー型" #: src/idioms/ffi/errors.md:109 src/idioms/ffi/accepting-strings.md:48 #: src/idioms/ffi/accepting-strings.md:83 src/patterns/creational/builder.md:30 #: src/patterns/ffi/export.md:137 src/patterns/ffi/export.md:139 msgid "/* ... */" -msgstr "" +msgstr "/* ... */" #: src/idioms/ffi/errors.md:111 msgid "/* Create a second version which is exposed as a C structure */" -msgstr "" +msgstr "/* C 言語向けに公開するバージョンを別に定義 */" #: src/idioms/ffi/errors.md:130 msgid "" "This ensures that the foreign language has clear access to error information " "while not compromising the Rust code's API at all." msgstr "" +"この手法を使えば、他言語側からエラー情報に明確にアクセスできるようになりま" +"す。同時に、Rust 側の API 設計においても一切の妥協が不要です。" #: src/idioms/ffi/errors.md:135 msgid "" "It's a lot of typing, and some types may not be able to be converted easily " "to C." msgstr "" +"記述量が多くなりがちで、また型によってはC に変換しづらい場合があります。" #: src/idioms/ffi/accepting-strings.md:5 msgid "" From 3298afb582d4ae04427573e06944b09db03792b5 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Fri, 23 May 2025 21:57:52 +0900 Subject: [PATCH 11/12] Japanese translation: Accepting Strings --- po/ja.po | 65 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/po/ja.po b/po/ja.po index 9f38a0e5..536f3484 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-23 00:10+0900\n" +"PO-Revision-Date: 2025-05-23 21:56+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -1786,38 +1786,47 @@ msgid "" "When accepting strings via FFI through pointers, there are two principles " "that should be followed:" msgstr "" +"FFI 経由でポインタとして文字列を受け取る場合には、次の2つの原則を守るべきで" +"す:" #: src/idioms/ffi/accepting-strings.md:8 msgid "Keep foreign strings \"borrowed\", rather than copying them directly." -msgstr "" +msgstr "外部の文字列は 直接コピーするのではなく「借用」 として扱うこと。" #: src/idioms/ffi/accepting-strings.md:9 msgid "" "Minimize the amount of complexity and `unsafe` code involved in converting " "from a C-style string to native Rust strings." msgstr "" +"Cスタイルの文字列から Rust の文字列への変換において、複雑さと `unsafe` コード" +"の使用を最小限に抑えること。" #: src/idioms/ffi/accepting-strings.md:14 msgid "" "The strings used in C have different behaviours to those used in Rust, " "namely:" msgstr "" +"C言語の文字列と Rust の文字列は、仕様と扱いが大きく異なります。たとえば:" #: src/idioms/ffi/accepting-strings.md:16 msgid "C strings are null-terminated while Rust strings store their length" -msgstr "" +msgstr "C の文字列は null終端だが、Rust の文字列は 長さ情報を保持" #: src/idioms/ffi/accepting-strings.md:17 msgid "" "C strings can contain any arbitrary non-zero byte while Rust strings must be " "UTF-8" msgstr "" +"C の文字列は 任意の非ゼロバイトを含めることができる が、Rust の文字列は " +"UTF-8 準拠である必要がある" #: src/idioms/ffi/accepting-strings.md:19 msgid "" "C strings are accessed and manipulated using `unsafe` pointer operations " "while interactions with Rust strings go through safe methods" msgstr "" +"C の文字列操作は `unsafe` なポインタ操作だが、Rust の文字列操作は安全な API " +"で行える" #: src/idioms/ffi/accepting-strings.md:22 msgid "" @@ -1826,18 +1835,23 @@ msgid "" "complexity and `unsafe` code involved in converting between C strings and " "Rust strings." msgstr "" +"Rust の標準ライブラリには、C 言語との橋渡し用として `String` / `&str` に対応" +"する型である。`CString` および `&CStr` が用意されています。これにより、複雑な" +"処理や `unsafe` コードの多くを回避することができます。" #: src/idioms/ffi/accepting-strings.md:26 msgid "" "The `&CStr` type also allows us to work with borrowed data, meaning passing " "strings between Rust and C is a zero-cost operation." msgstr "" +"さらに `&CStr` 型は 借用として動作する ため、Rust と C 間での文字列受け渡しが" +"ゼロコストで行えるという利点もあります。" #: src/idioms/ffi/accepting-strings.md:34 #: src/idioms/ffi/accepting-strings.md:77 src/idioms/ffi/passing-strings.md:31 #: src/idioms/ffi/passing-strings.md:80 src/patterns/ffi/wrappers.md:114 msgid "// other module content\n" -msgstr "" +msgstr "// その他のモジュール内容...\n" #: src/idioms/ffi/accepting-strings.md:36 msgid "" @@ -1852,67 +1866,87 @@ msgid "" " /// - points to memory ending in a null byte\n" " /// - won't be mutated for the duration of this function call\n" msgstr "" +"/// 指定されたログレベルでメッセージを記録する\n" +" ///\n" +" /// # Safety\n" +" ///\n" +" /// 呼び出し側は `msg` が以下を満たすことを保証しなければならない:\n" +" /// - null ポインタではないこと\n" +" /// - 有効かつ初期化済みのデータを指していること\n" +" /// - 終端に null バイトがあること\n" +" /// - 関数呼び出し中に内容が変更されないこと\n" #: src/idioms/ffi/accepting-strings.md:50 msgid "" "// SAFETY: The caller has already guaranteed this is okay (see the\n" " // `# Safety` section of the doc-comment).\n" msgstr "" +"// SAFETY: この操作が安全であることは、呼び出し側がすでに保証しています。\n" +"// 詳細はドキュメントコメント内の `# Safety` セクションを参照してください。\n" #: src/idioms/ffi/accepting-strings.md:55 #: src/idioms/ffi/accepting-strings.md:105 msgid "\"FFI string conversion failed\"" -msgstr "" +msgstr "\"FFI string conversion failed\"" #: src/idioms/ffi/accepting-strings.md:67 msgid "The example is written to ensure that:" -msgstr "" +msgstr "この実装には次のような利点があります:" #: src/idioms/ffi/accepting-strings.md:69 src/idioms/ffi/passing-strings.md:70 msgid "The `unsafe` block is as small as possible." -msgstr "" +msgstr "`unsafe` ブロックを 可能な限り最小化 している" #: src/idioms/ffi/accepting-strings.md:70 msgid "" "The pointer with an \"untracked\" lifetime becomes a \"tracked\" shared " "reference" msgstr "" +"“ライフタイムが追跡されないポインタ” を、追跡可能な借用参照へと昇格させている" #: src/idioms/ffi/accepting-strings.md:72 msgid "Consider an alternative, where the string is actually copied:" -msgstr "" +msgstr "以下は、文字列がコピーされてしまう方法です:" #: src/idioms/ffi/accepting-strings.md:80 msgid "" "// DO NOT USE THIS CODE.\n" " // IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG.\n" msgstr "" +"// このコードは使わないでください。\n" +" // 冗長で読みづらく、しかも微妙なバグを含んでいます。\n" #: src/idioms/ffi/accepting-strings.md:85 msgid "/* SAFETY: strlen is what it is, I guess? */" -msgstr "" +msgstr "/* SAFETY: strlen だから仕方ない…? */" #: src/idioms/ffi/accepting-strings.md:92 msgid "" "// SAFETY: copying from a foreign pointer expected to live\n" " // for the entire stack frame into owned memory\n" msgstr "" +"// SAFETY: スタックフレームの存続期間全体にわたって\n" +" // 有効であると想定される外部ポインタから、所有メモリへコピーして" +"います。\n" #: src/idioms/ffi/accepting-strings.md:116 msgid "This code is inferior to the original in two respects:" -msgstr "" +msgstr "このコードは次の2点において、前の実装より劣っています:" #: src/idioms/ffi/accepting-strings.md:118 msgid "" "There is much more `unsafe` code, and more importantly, more invariants it " "must uphold." msgstr "" +"`unsafe` コードがはるかに多く、重要なことは、それによって維持すべき不変条件も" +"多くなっていることです。" #: src/idioms/ffi/accepting-strings.md:120 msgid "" "Due to the extensive arithmetic required, there is a bug in this version " "that cases Rust `undefined behaviour`." msgstr "" +"複雑なポインタ演算により、Rust 的な未定義動作を引き起こすバグを含んでいます" #: src/idioms/ffi/accepting-strings.md:123 msgid "" @@ -1920,6 +1954,8 @@ msgid "" "copied, all `msg_len` bytes of it. However, the `NUL` terminator at the end " "was not." msgstr "" +"具体的には、ポインタから `msg_len` バイトをコピーしていますが、終端の `NUL` " +"バイトは含まれていません。" #: src/idioms/ffi/accepting-strings.md:126 msgid "" @@ -1929,6 +1965,11 @@ msgid "" "`CString` is created at the bottom of the block, its read of the Vector will " "cause `undefined behaviour`!" msgstr "" +"その後、ベクタのサイズは _ゼロ埋めされた文字列_ の長さに _set_ されました" +"が、 _resized_ されたわけではありません。リサイズされていれば末尾に 0 が追加" +"された可能性がありました。その結果、ベクタの最後のバイトは 初期化されていない" +"メモリのまま になっています。ブロックの末尾で `CString` が作成される際に、そ" +"のベクタを読み取る処理が行われ、結果として未定義動作が発生します!" #: src/idioms/ffi/accepting-strings.md:132 msgid "" @@ -1937,11 +1978,13 @@ msgid "" "would put a weird character at the end of the string, sometimes it would " "just completely crash." msgstr "" +"このようなバグは検出が難しく、非 `UTF-8` として panic を起こすこともあれば、" +"末尾に謎の文字がついたり、あるいは完全にクラッシュすることもあります。" #: src/idioms/ffi/accepting-strings.md:138 #: src/idioms/ffi/passing-strings.md:103 msgid "None?" -msgstr "" +msgstr "なし?" #: src/idioms/ffi/passing-strings.md:5 msgid "" From 85da75668f603f5479506b164daf46e8f140db00 Mon Sep 17 00:00:00 2001 From: Koji Murata Date: Fri, 23 May 2025 22:00:38 +0900 Subject: [PATCH 12/12] Japanese translation: fix --- po/ja.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/po/ja.po b/po/ja.po index 536f3484..7682c523 100644 --- a/po/ja.po +++ b/po/ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Rust Design Patterns\n" "POT-Creation-Date: 2025-05-17T14:07:35+09:00\n" -"PO-Revision-Date: 2025-05-23 21:56+0900\n" +"PO-Revision-Date: 2025-05-23 21:59+0900\n" "Last-Translator: Koji Murata \n" "Language-Team: Japanese \n" "Language: ja\n" @@ -1836,7 +1836,7 @@ msgid "" "Rust strings." msgstr "" "Rust の標準ライブラリには、C 言語との橋渡し用として `String` / `&str` に対応" -"する型である。`CString` および `&CStr` が用意されています。これにより、複雑な" +"する型である、`CString` および `&CStr` が用意されています。これにより、複雑な" "処理や `unsafe` コードの多くを回避することができます。" #: src/idioms/ffi/accepting-strings.md:26 @@ -1918,7 +1918,7 @@ msgstr "" #: src/idioms/ffi/accepting-strings.md:85 msgid "/* SAFETY: strlen is what it is, I guess? */" -msgstr "/* SAFETY: strlen だから仕方ない…? */" +msgstr "/* SAFETY: strlen はこういうものだから仕方ない…? */" #: src/idioms/ffi/accepting-strings.md:92 msgid ""