From ef9409aa719b43f1187f642471583f2be5877ead Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 1 Aug 2019 14:21:13 -0700 Subject: [PATCH 001/217] Mention --cap-lints on #[deny(warnings)] page --- anti_patterns/deny-warnings.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index ea0c869d..e019c765 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -35,7 +35,8 @@ before there was none. All this conspires to potentially break the build whenever something changes. Furthermore, crates that supply additional lints (e.g. [rust-clippy]) can no -longer be used unless the annotation is removed. +longer be used unless the annotation is removed. This is mitigated with +[--cap-lints]. ## Alternatives @@ -108,3 +109,4 @@ certain that there will be more deprecated APIs in the future. [rust-clippy]: https://github.com/Manishearth/rust-clippy [deprecate attribute]: https://doc.rust-lang.org/reference/attributes.html#deprecation +[--cap-lints]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints From 6566500a702543ec076d73d095605cbcf107675d Mon Sep 17 00:00:00 2001 From: Alexey Gerasimov Date: Sat, 28 Sep 2019 19:42:34 +0500 Subject: [PATCH 002/217] Type fix --- anti_patterns/deref.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index 8dccea50..a5a69849 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -57,7 +57,7 @@ version (probably, you should use `#[repr(C)]` if you want to be sure)). 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 `Foo` (for example, using `*`) then we will get a `Bar`. That is +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 From 396ae01fdd31cc7fc4229066412b65ce21726bc1 Mon Sep 17 00:00:00 2001 From: Kinsey Favre Date: Thu, 6 Feb 2020 16:56:39 -0600 Subject: [PATCH 003/217] Rewrite mentions of `try!` macro to use `?` operator The `try!` macro has been [deprecated since Rust 1.39.0][1] in favor of the `?` operator; update text using it to reflect this. [1]: https://doc.rust-lang.org/std/macro.try.html --- idioms/dtor-finally.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index a06cea66..b7edf52f 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -23,8 +23,8 @@ fn bar() -> Result<(), ()> { // The dtor of _exit will run however the function `bar` is exited. let _exit = Foo; - // Implicit return in try!. - try!(baz()); + // Implicit return with `?` operator. + baz()?; // Normal return. Ok(()) } @@ -35,11 +35,11 @@ fn bar() -> Result<(), ()> { If a function has multiple return points, then executing code on exit 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 `try!` which returns if the -result is an `Err`, but continues if it is `Ok`. `try!` 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. +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. ## Advantages From 5ebfc0cdc5e5e98b0174c2ee46ba83b6eb021cee Mon Sep 17 00:00:00 2001 From: kellerkindt Date: Thu, 5 Mar 2020 11:28:58 +0100 Subject: [PATCH 004/217] Show call of default() --- idioms/default.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/idioms/default.md b/idioms/default.md index e78c672c..5abcc2a7 100644 --- a/idioms/default.md +++ b/idioms/default.md @@ -36,6 +36,12 @@ struct MyConfiguration { impl MyConfiguration { // add setters here } + +fn main() { + // construct a new instance with default values + let mut conf = MyConfiguration::default(); + // do somthing with conf here +} ``` ## See also From 9327f4647877d0a5cc68c539b0d79f17f6415691 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 25 Apr 2020 17:22:55 +0200 Subject: [PATCH 005/217] Add TODOs for module and FFI topics --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1f2ae0c5..32baa410 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ language. * [Pass variables to closure](idioms/pass-var-to-closure.md) * [`mem::replace(_)` to avoid needless clones](idioms/mem-replace.md) * [Temporary mutability](idioms/temporary-mutability.md) +* TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) ### Design patterns @@ -34,6 +35,7 @@ language. * TODO closures and lifetimes (coupling to lifetime) * TODO platform-specific sub-modules (https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md#platform-specific-opt-in) * [Entry API](patterns/entry.md) (Currently just a boilerplate) +* TODO Module organisation (by looking at examples such as Rusts `libstd`, and how it integrated into the Rusts source code, lessons can be learned about ergonomic project management and API design. Closely assosciated with platform-specific sub-modules) * [Visitor](patterns/visitor.md) * [Fold](patterns/fold.md) * [Prefer small crates](patterns/small-crates.md) From a18cbf48a65c037d6c2b44e410129f5211d22f48 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 25 Apr 2020 17:23:33 +0200 Subject: [PATCH 006/217] Clarify that a topic is currently stubbed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32baa410..26b3629b 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ language. * TODO iterators (to safely avoid bounds checks) * TODO closures and lifetimes (coupling to lifetime) * TODO platform-specific sub-modules (https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md#platform-specific-opt-in) -* [Entry API](patterns/entry.md) (Currently just a boilerplate) * TODO Module organisation (by looking at examples such as Rusts `libstd`, and how it integrated into the Rusts source code, lessons can be learned about ergonomic project management and API design. Closely assosciated with platform-specific sub-modules) +* [Entry API](patterns/entry.md) (TODO Currently just a boilerplate) * [Visitor](patterns/visitor.md) * [Fold](patterns/fold.md) * [Prefer small crates](patterns/small-crates.md) From 399c38ee2b2a3f34ca594bc3c5e5af1d86516168 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 24 Mar 2020 07:43:37 +0100 Subject: [PATCH 007/217] New idiom: Out of the Box Dynamic Dispatch --- README.md | 1 + idioms/on-stack-dyn-dispatch.md | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 idioms/on-stack-dyn-dispatch.md diff --git a/README.md b/README.md index 26b3629b..95eac97b 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ language. * [Pass variables to closure](idioms/pass-var-to-closure.md) * [`mem::replace(_)` to avoid needless clones](idioms/mem-replace.md) * [Temporary mutability](idioms/temporary-mutability.md) +* [On-Stack Dynamic Dispatch](idioms/on-stack-dyn-dispatch.md) * TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) ### Design patterns diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md new file mode 100644 index 00000000..b1a8b436 --- /dev/null +++ b/idioms/on-stack-dyn-dispatch.md @@ -0,0 +1,83 @@ +# On-Stack Dynamic Dispatch + +## Description + +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 +lifetime as necessary, we can use deferred conditional initialization, as seen +below: + +## Example + +```rust +// These must live longer than `readable`, and thus are declared first: +let (mut stdin_read, mut file_read); + +// We need to ascribe the type to get dynamic dispatch. +let readable: &mut dyn io::Read = if arg == '-' { + stdin_read = io::stdin(); + &mut stdin_read +} else { + file_read = fs::File::open(arg)?; + &mut file_read +}; + +// Read from `readable` here. +``` + +## Motivation + +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 +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. + +Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly ask +for it. + +## Advantages + +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`, with all the + +## Disadvantages + +The code needs more moving parts than the `Box`-based version: + +``` +// We still need to ascribe the type for dynamic dispatch. +let readable: Box = if arg == "-" { + Box::new(io::stdin()) +} else { + Box::new(fs::File::open(arg)?) +}; +// Read from `readable` here. +``` + +## Discussion + +Rust newcomers will usually learn that Rust requires all variables to be +initialized *before use*, so it's easy to overlook the fact that *unused* +variables may well be uninitialized. Rust works quite hard to ensure that this +works out fine and only the initialized values are dropped at the end of their +scope. + +The example meets all the constraints Rust places on us: + +* All variables are initialized before using (in this case borrowing) them +* Each variable only holds values of a single type. In our example, `stdin` is +of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut dyn +Read` +* Each borrowed value outlives all the references borrowed from it + +## See also + +* [Finalisation in destructors](idioms/dtor-finally.md) and +[RAII guards](patterns/RAII.md) can benefit from tight control over lifetimes. +* For conditionally filled `Option<&T>`s of (mutable) references, one can +initialize an `Option` directly and use its [`.as_ref()`] method to get an +optional reference. + +[`.as_ref()`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.as_ref From 5310b14b62f9b8a506f09e9f3a694c24ee2b0c0b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Thu, 16 Jul 2020 23:19:34 -0700 Subject: [PATCH 008/217] Add example for #91 --- README.md | 1 + idioms/rustdoc-init.md | 73 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 idioms/rustdoc-init.md diff --git a/README.md b/README.md index 95eac97b..8ebdca44 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ language. * [Temporary mutability](idioms/temporary-mutability.md) * [On-Stack Dynamic Dispatch](idioms/on-stack-dyn-dispatch.md) * TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) +* [Easy doc initialization](idioms/rustdoc-init.md) ### Design patterns diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md new file mode 100644 index 00000000..37035bc0 --- /dev/null +++ b/idioms/rustdoc-init.md @@ -0,0 +1,73 @@ +# Easy doc initialization + +## Description + +If a struct takes significant effort to initialize, when writing docs it can be quicker to wrap your example with a +function the struct as an argument. + +## Motivation +Sometimes there is a struct with multiple or complicated parameters and several methods. +Each of these methods should have examples. + +For example: + +```rust +struct ExampleStruct { + foo: Box, + count: AtomicI64, +} + +impl ExampleStruct { + /// Does something important. + /// # Example + /// ``` + /// # //This is some really borring boiler plate to get an example working. + /// # let baz = Baz::new(Bat::new(0, 1), 2, "Foo".to_owned()); + /// # let foo = Box::new(Foo::new(baz)); + /// # let example_struct = ExampleStruct{ foo: foo, count: AtomicI64::new(3) }; + /// let result = example_struct.bar(); + /// // do stuff with result. + /// ``` + fn bar() -> u64 { + + } + + /// Oh no all that boiler plate needs to be repeated here !!! + fn other_method() { + } +} +``` + +## Example +Instead of typing all of this boiler plate to create an `ExampleStruct` it is easier to just create a dummy method to pass one in: +```rust +struct ExampleStruct { + foo: Box, + count: AtomicI64, +} +impl ExampleStruct { + /// Does something important. + /// # Example + /// ``` + /// # fn call_bar(example_struct: ExampleStruct) { + /// let result = example_struct.bar(); + /// // do stuff with result. + /// # } +} +``` +## Advantages + +This is much more concise and avoids repetitive code in examples. + +## Disadvantages + +Because the example is in a function, the code won't actually be tested. +It still will be compiled when running a `cargo test` but assertions can't be used to verify properties. + +## Discussion + +If assertions are not required this pattern works well. +If they are, an alternative can be to create a method to create a dummy instance which is annotated with: + +`#[doc(hidden)]` + From 3714ca26061cbc59301c251d3f7e875857d99c9b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Thu, 23 Jul 2020 13:05:16 -0700 Subject: [PATCH 009/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 37035bc0..1f837ee5 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -50,7 +50,7 @@ impl ExampleStruct { /// # Example /// ``` /// # fn call_bar(example_struct: ExampleStruct) { - /// let result = example_struct.bar(); + /// let result = example_struct.bar(); /// // do stuff with result. /// # } } @@ -70,4 +70,3 @@ If assertions are not required this pattern works well. If they are, an alternative can be to create a method to create a dummy instance which is annotated with: `#[doc(hidden)]` - From faacbbcf7a8b68b9b6b80e7f35eb30114c310d7e Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Thu, 23 Jul 2020 13:31:54 -0700 Subject: [PATCH 010/217] Make example more explicet --- idioms/rustdoc-init.md | 62 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 37035bc0..028d558d 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -12,47 +12,57 @@ Each of these methods should have examples. For example: ```rust -struct ExampleStruct { - foo: Box, - count: AtomicI64, + +struct Connection { + name: String, + stream: TcpStream, + //... } -impl ExampleStruct { - /// Does something important. +impl Connection { + /// Sends a request over the connection. /// # Example - /// ``` + /// ```no_run /// # //This is some really borring boiler plate to get an example working. - /// # let baz = Baz::new(Bat::new(0, 1), 2, "Foo".to_owned()); - /// # let foo = Box::new(Foo::new(baz)); - /// # let example_struct = ExampleStruct{ foo: foo, count: AtomicI64::new(3) }; - /// let result = example_struct.bar(); + /// # let stream = TcpStream::connect("127.0.0.1:34254"); + /// # let connection = Connection{ name: "Foo".to_owned(), stream: stream }; + /// # let request = Request::new("ReuqestId", RequestType::Get, "dummy_payload"); + /// let result = connection.send_reqest(request); /// // do stuff with result. /// ``` - fn bar() -> u64 { - + fn send_reqest(&self, request: Request) -> Result { + //... } - + /// Oh no all that boiler plate needs to be repeated here !!! - fn other_method() { + fn check_status(&self) -> Status { + //... } } ``` ## Example -Instead of typing all of this boiler plate to create an `ExampleStruct` it is easier to just create a dummy method to pass one in: +Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just create a wrapping dummy function which takes them as arguments: ```rust -struct ExampleStruct { - foo: Box, - count: AtomicI64, + +struct Connection { + name: String, + stream: TcpStream, + //... } -impl ExampleStruct { - /// Does something important. + +impl Connection { + /// Sends a request over the connection. /// # Example /// ``` - /// # fn call_bar(example_struct: ExampleStruct) { - /// let result = example_struct.bar(); + /// # fn call_send(connection: Connection, request: Request) { + /// let result = connection.send_reqest(); /// // do stuff with result. /// # } + /// ``` + fn send_reqest(&self, request: Request) { + //... + } } ``` ## Advantages @@ -61,13 +71,13 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages -Because the example is in a function, the code won't actually be tested. -It still will be compiled when running a `cargo test` but assertions can't be used to verify properties. +Because the example is in a function, the code won't actually be tested. (Though it still will checked to make sure it compiles when running a `cargo test`) +So this pattern is most useful when you would need to add `no_run` anyway. ## Discussion If assertions are not required this pattern works well. -If they are, an alternative can be to create a method to create a dummy instance which is annotated with: -`#[doc(hidden)]` +If they are, an alternative can be to create a public method to create a dummy instance which is annotated with `#[doc(hidden)]` (so that users won't see it). +Then this method can be called inside of Rustdocs because it is part of the crate's public API. From 87245c7d17f1dbeb350777c61c1cff422140d54b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:42:36 -0700 Subject: [PATCH 011/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 028d558d..4db9b304 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -12,7 +12,6 @@ Each of these methods should have examples. For example: ```rust - struct Connection { name: String, stream: TcpStream, @@ -80,4 +79,3 @@ If assertions are not required this pattern works well. If they are, an alternative can be to create a public method to create a dummy instance which is annotated with `#[doc(hidden)]` (so that users won't see it). Then this method can be called inside of Rustdocs because it is part of the crate's public API. - From 46493aa6c1efd819722253255d07504fd91fb08b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:42:49 -0700 Subject: [PATCH 012/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 1 - 1 file changed, 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 4db9b304..cf7b9d61 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -15,7 +15,6 @@ For example: struct Connection { name: String, stream: TcpStream, - //... } impl Connection { From 2a44fbdb55b1d04155917847237bf0946d65d113 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:43:02 -0700 Subject: [PATCH 013/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index cf7b9d61..73742a72 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -21,7 +21,7 @@ impl Connection { /// Sends a request over the connection. /// # Example /// ```no_run - /// # //This is some really borring boiler plate to get an example working. + /// # // Boilerplate are required to get an example working. /// # let stream = TcpStream::connect("127.0.0.1:34254"); /// # let connection = Connection{ name: "Foo".to_owned(), stream: stream }; /// # let request = Request::new("ReuqestId", RequestType::Get, "dummy_payload"); From 1761b3b5ce55500c21cd26e78453ddc6e480f88b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:43:40 -0700 Subject: [PATCH 014/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 73742a72..69d63d9c 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -23,12 +23,12 @@ impl Connection { /// ```no_run /// # // Boilerplate are required to get an example working. /// # let stream = TcpStream::connect("127.0.0.1:34254"); - /// # let connection = Connection{ name: "Foo".to_owned(), stream: stream }; - /// # let request = Request::new("ReuqestId", RequestType::Get, "dummy_payload"); - /// let result = connection.send_reqest(request); - /// // do stuff with result. + /// # let connection = Connection { name: "foo".to_owned(), stream }; + /// # let request = Request::new("RequestId", RequestType::Get, "payload"); + /// let response = connection.send_request(request); + /// assert!(response.is_ok()); /// ``` - fn send_reqest(&self, request: Request) -> Result { + fn send_request(&self, request: Request) -> Result { //... } From a2988fe94e697598cd5ba5c9ad9ad4291b92a50a Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:43:51 -0700 Subject: [PATCH 015/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 69d63d9c..e4715fec 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -32,7 +32,7 @@ impl Connection { //... } - /// Oh no all that boiler plate needs to be repeated here !!! + /// Oh no, all that boilerplate needs to be repeated here! fn check_status(&self) -> Status { //... } From 1571a7ae1987738db42e945a4d6046b8949f67e2 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:43:59 -0700 Subject: [PATCH 016/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index e4715fec..94d3b2ab 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -34,7 +34,7 @@ impl Connection { /// Oh no, all that boilerplate needs to be repeated here! fn check_status(&self) -> Status { - //... + // ... } } ``` From 2a4eaff0db71bd5258afd168655911c0baf8747b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:44:06 -0700 Subject: [PATCH 017/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 94d3b2ab..ce5b4dae 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -29,7 +29,7 @@ impl Connection { /// assert!(response.is_ok()); /// ``` fn send_request(&self, request: Request) -> Result { - //... + // ... } /// Oh no, all that boilerplate needs to be repeated here! From f2e471027a17e9a9aebec27d2de1aa8e7d40ace5 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:44:14 -0700 Subject: [PATCH 018/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 1 - 1 file changed, 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index ce5b4dae..38b90646 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -46,7 +46,6 @@ Instead of typing all of this boiler plate to create an `Connection` and `Reques struct Connection { name: String, stream: TcpStream, - //... } impl Connection { From 625b5017da70ce5c7d64e9a99fde972a755569f8 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:44:24 -0700 Subject: [PATCH 019/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 1 + 1 file changed, 1 insertion(+) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 38b90646..d4dcd5ca 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -19,6 +19,7 @@ struct Connection { impl Connection { /// Sends a request over the connection. + /// /// # Example /// ```no_run /// # // Boilerplate are required to get an example working. From f62a79db7fa50788ba0fddd3a95d213328c19881 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:44:33 -0700 Subject: [PATCH 020/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 1 + 1 file changed, 1 insertion(+) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index d4dcd5ca..4e02d802 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -51,6 +51,7 @@ struct Connection { impl Connection { /// Sends a request over the connection. + /// /// # Example /// ``` /// # fn call_send(connection: Connection, request: Request) { From 2dcf58a049c57396ca26a43f50fa2ae90bd8e0dd Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:45:17 -0700 Subject: [PATCH 021/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 4e02d802..93828fe3 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -70,7 +70,7 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages -Because the example is in a function, the code won't actually be tested. (Though it still will checked to make sure it compiles when running a `cargo test`) +As example is in a function, the code will not be tested. (Though it still will checked to make sure it compiles when running a `cargo test`) So this pattern is most useful when you would need to add `no_run` anyway. ## Discussion From c642018eeec9eebe0c926f94db81152b854aa8f5 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:45:59 -0700 Subject: [PATCH 022/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 93828fe3..26fc895c 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -71,7 +71,7 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages As example is in a function, the code will not be tested. (Though it still will checked to make sure it compiles when running a `cargo test`) -So this pattern is most useful when you would need to add `no_run` anyway. +So this pattern is most useful when need `no_run`. With this, you do not need to add `no_run`. ## Discussion From 1e62aa59f8c772b3fd5235367bc993f09dc2ba9b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:46:08 -0700 Subject: [PATCH 023/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 26fc895c..889041a1 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -78,4 +78,4 @@ So this pattern is most useful when need `no_run`. With this, you do not need to If assertions are not required this pattern works well. If they are, an alternative can be to create a public method to create a dummy instance which is annotated with `#[doc(hidden)]` (so that users won't see it). -Then this method can be called inside of Rustdocs because it is part of the crate's public API. +Then this method can be called inside of rustdoc because it is part of the crate's public API. From 7e416d0c995496758d0ea4ad6a89209fcc348753 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:47:06 -0700 Subject: [PATCH 024/217] Update idioms/rustdoc-init.md Co-authored-by: Ivan Tham --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 889041a1..ff4fff05 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -42,8 +42,8 @@ impl Connection { ## Example Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just create a wrapping dummy function which takes them as arguments: -```rust +```rust struct Connection { name: String, stream: TcpStream, From 9a9245cad852bc729db3ca1a3e7d482f9b2fc0f0 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 26 Jul 2020 23:54:23 -0700 Subject: [PATCH 025/217] Update rustdoc-init.md Add comment per feedback --- idioms/rustdoc-init.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index ff4fff05..1d687d17 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -55,15 +55,17 @@ impl Connection { /// # Example /// ``` /// # fn call_send(connection: Connection, request: Request) { - /// let result = connection.send_reqest(); - /// // do stuff with result. + /// let response = connection.send_request(); + /// assert!(response.is_ok()); /// # } /// ``` - fn send_reqest(&self, request: Request) { - //... + fn send_request(&self, request: Request) { + // ... } } ``` +**Note** in the above example the line `assert!(response.is_ok());` will not actually run while testing because it is inside of a function which is never invoked. + ## Advantages This is much more concise and avoids repetitive code in examples. From 8b3cd45d9e151aef48412dc09f5d5b15373b9715 Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Mon, 10 Aug 2020 11:57:37 +0300 Subject: [PATCH 026/217] Fix typos --- idioms/on-stack-dyn-dispatch.md | 2 +- idioms/rustdoc-init.md | 4 ++-- patterns/RAII.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index b1a8b436..ee677625 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -46,7 +46,7 @@ whole code that follows to work with both `File` or `Stdin`, with all the The code needs more moving parts than the `Box`-based version: -``` +```rust // We still need to ascribe the type for dynamic dispatch. let readable: Box = if arg == "-" { Box::new(io::stdin()) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 1d687d17..60d6c9b4 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -2,8 +2,8 @@ ## Description -If a struct takes significant effort to initialize, when writing docs it can be quicker to wrap your example with a -function the struct as an argument. +If a struct takes significant effort to initialize, when writing docs, it can be quicker to wrap your example with a +function which takes the struct as an argument. ## Motivation Sometimes there is a struct with multiple or complicated parameters and several methods. diff --git a/patterns/RAII.md b/patterns/RAII.md index 8f910bbe..9da6a0d6 100644 --- a/patterns/RAII.md +++ b/patterns/RAII.md @@ -113,5 +113,5 @@ RAII is a common pattern in C++: [cppreference.com](http://en.cppreference.com/w [wikipedia]: https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization -[Style guide enty](http://doc.rust-lang.org/stable/style/ownership/raii.html) +[Style guide entry](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html) (currently just a placeholder). From 1d606a511640f2095ae7c3bb723cda1ce5b91dae Mon Sep 17 00:00:00 2001 From: Richard Walters Date: Thu, 31 Dec 2020 03:41:09 -0800 Subject: [PATCH 027/217] Fix broken links (#105) * Fix broken links Fix broken link from `on-stack-dyn-dispatch.md` to `dtor-finally.md`. Link to `RAII.md` was broken as well. --- idioms/on-stack-dyn-dispatch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index ee677625..e4dc011d 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -74,8 +74,8 @@ Read` ## See also -* [Finalisation in destructors](idioms/dtor-finally.md) and -[RAII guards](patterns/RAII.md) can benefit from tight control over lifetimes. +* [Finalisation in destructors](dtor-finally.md) and +[RAII guards](../patterns/RAII.md) can benefit from tight control over lifetimes. * For conditionally filled `Option<&T>`s of (mutable) references, one can initialize an `Option` directly and use its [`.as_ref()`] method to get an optional reference. From 3f3ae4ae731bb4e5e8edb7c1cc3f24da48949dcd Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:27:42 +0100 Subject: [PATCH 028/217] Adding mdbook configuration and deployment to gh-pages (#111) --- .env | 1 + .github/workflows/gh-pages.yml | 31 +++++++++++++++++++++++++++++++ .gitignore | 2 ++ README.md | 17 +++++++++++++++++ SUMMARY.md | 32 ++++++++++++++++++++++++++++++++ anti_patterns/README.md | 3 +++ book.toml | 20 ++++++++++++++++++++ idioms/README.md | 3 +++ patterns/README.md | 3 +++ 9 files changed, 112 insertions(+) create mode 100644 .env create mode 100644 .github/workflows/gh-pages.yml create mode 100644 .gitignore create mode 100644 SUMMARY.md create mode 100644 anti_patterns/README.md create mode 100644 book.toml create mode 100644 idioms/README.md create mode 100644 patterns/README.md diff --git a/.env b/.env new file mode 100644 index 00000000..82f6f280 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +MDBOOK_VERSION=0.4.4 diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 00000000..b0b8e2f7 --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,31 @@ +name: github pages + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Read .env + id: mdbook-version + run: | + . ./.env + echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" + + - name: Setup mdbook + uses: peaceiris/actions-mdbook@v1 + with: + mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' + + - run: mdbook build + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./book diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..851a43b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Generated output of mdbook +/book diff --git a/README.md b/README.md index 8ebdca44..03093c66 100644 --- a/README.md +++ b/README.md @@ -78,3 +78,20 @@ We suggest leaving a comment on the [issue tracker](https://github.com/rust-unof so that other people don't start working on the same topic. Correction and elaboration PRs are very welcome. + +## Building with mdbook + +This book is built with [mdbook](https://rust-lang.github.io/mdBook/). You can install it by running `cargo install mdbook`. + +If you want to build it locally you can run one of these two commands in the root directory of the repository: + +- `mdbook build` + + Builds static html pages as output and place them in the `/book` directory by default. + +- `mdbook serve` + + Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output + to be sure) and reloads the browser when a change occurs. + + \ No newline at end of file diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 00000000..5a56e465 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,32 @@ +# Summary + +- [Introduction](./intro.md) +- [Idioms](./idioms/README.md) + - [Concatenating Strings with `format!`](./idioms/concat-format.md) + - [Constructor](./idioms/ctor.md) + - [The `Default` Trait](./idioms/default.md) + - [Collections Are Smart Pointers](./idioms/deref.md) + - [Finalisation in Destructors](./idioms/dtor-finally.md) + - [`mem::replace(_)`](./idioms/mem-replace.md) + - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) + - [Iterating over an `Option`](./idioms/option-iter.md) + - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) + - [Privacy For Extensibility](./idioms/priv-extend.md) + - [Easy doc initialization](./idioms/rustdoc-init.md) + - [Temporary mutability](./idioms/temporary-mutability.md) + +- [Design Patterns](./patterns/README.md) + - [Builder](./patterns/builder.md) + - [Compose Structs](./patterns/compose-structs.md) + - [Entry API](./patterns/entry.md) + - [Fold](./patterns/fold.md) + - [Late Bound Bounds](./patterns/late-bounds.md) + - [Newtype](./patterns/newtype.md) + - [RAII Guards](./patterns/RAII.md) + - [Prefer Small Crates](./patterns/small-crates.md) + - [Contain unsafety in small modules](./patterns/unsafe-mods.md) + - [Visitor](./patterns/visitor.md) + +- [Anti-patterns](./anti_patterns/README.md) + - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) + - [Deref Polymorphism](./anti_patterns/deref.md) diff --git a/anti_patterns/README.md b/anti_patterns/README.md new file mode 100644 index 00000000..c318b4d0 --- /dev/null +++ b/anti_patterns/README.md @@ -0,0 +1,3 @@ +# Anti-patterns + +TODO: add description/explanation diff --git a/book.toml b/book.toml new file mode 100644 index 00000000..c43d6724 --- /dev/null +++ b/book.toml @@ -0,0 +1,20 @@ +[book] +title = "Rust Design Patterns" +authors = ["the rust-unofficial authors"] +description = "A catalogue of Rust design patterns, anti-patterns and idioms" +language = "en" +multilingual = false +src = "." + +[build] +create-missing = false + +[rust] +edition = "2018" + +[output.html] +default-theme = "rust" +git-repository-url = "https://github.com/rust-unofficial/patterns" +git-repository-icon = "fa-github" + +# [output.linkcheck] # enable the "mdbook-linkcheck" renderer, disabled due to gh-actions diff --git a/idioms/README.md b/idioms/README.md new file mode 100644 index 00000000..6b680191 --- /dev/null +++ b/idioms/README.md @@ -0,0 +1,3 @@ +# Idioms + +TODO: add description/explanation diff --git a/patterns/README.md b/patterns/README.md new file mode 100644 index 00000000..c80b4371 --- /dev/null +++ b/patterns/README.md @@ -0,0 +1,3 @@ +# Design Patterns + +TODO: add description/explanation From 85efbe7fc382174637b2b0859e18266b89ae6e7a Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Fri, 1 Jan 2021 12:49:45 +0100 Subject: [PATCH 029/217] add ci (#115) --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..fd33f2f1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: Continuous Integration + +on: + push: + branches: [master] + pull_request: + +jobs: + + test: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Read .env + id: mdbook-version + run: | + . ./.env + echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v1 + with: + mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' + + - run: mdbook build From 66ce03a774f2dd4d952338a02aa9e5eec9733d06 Mon Sep 17 00:00:00 2001 From: wangcong Date: Fri, 1 Jan 2021 21:23:29 +0800 Subject: [PATCH 030/217] Fix wording in "Fold" pattern (#69) Co-authored-by: Chris Wong --- patterns/fold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/fold.md b/patterns/fold.md index 1b064bf6..4d70d4f9 100644 --- a/patterns/fold.md +++ b/patterns/fold.md @@ -100,7 +100,7 @@ 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. If we were to operate on borrowed references, the original data structure can be -reused, however, if a node is unchanged it must be cloned, which can be +reused; however, a node must be cloned even if unchanged, which can be expensive. Using a reference counted pointer gives the best of both worlds - we can reuse From de7519f5d937c4ff9f65928b3786cadc225bc130 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:15:33 +0100 Subject: [PATCH 031/217] Add introductions (#117) Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- README.md | 8 +++---- SUMMARY.md | 3 +++ anti_patterns/README.md | 5 +++- functional/README.md | 53 +++++++++++++++++++++++++++++++++++++++++ idioms/README.md | 8 ++++++- intro.md | 18 +++++++++++--- patterns/README.md | 20 +++++++++++++++- patterns/newtype.md | 4 ++++ refactoring/README.md | 15 ++++++++++++ 9 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 functional/README.md create mode 100644 refactoring/README.md diff --git a/README.md b/README.md index 03093c66..0f74fbd4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Rust Design Patterns -An open source repository of design patterns and idioms in the Rust programming -language. +An open source book about design patterns and idioms in the Rust programming +language that you can read [here](https://rust-unofficial.github.io/patterns/). ## Contents @@ -28,6 +28,7 @@ language. * TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) * [Easy doc initialization](idioms/rustdoc-init.md) + ### Design patterns * [Builder](patterns/builder.md) @@ -53,7 +54,6 @@ language. * [Compose structs together for better borrowing](patterns/compose-structs.md) - ### Anti-patterns * TODO thread + catch_panic for exceptions @@ -94,4 +94,4 @@ If you want to build it locally you can run one of these two commands in the roo Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output to be sure) and reloads the browser when a change occurs. - \ No newline at end of file + diff --git a/SUMMARY.md b/SUMMARY.md index 5a56e465..a8de1896 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,7 @@ # Summary - [Introduction](./intro.md) + - [Idioms](./idioms/README.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) - [Constructor](./idioms/ctor.md) @@ -30,3 +31,5 @@ - [Anti-patterns](./anti_patterns/README.md) - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) - [Deref Polymorphism](./anti_patterns/deref.md) + +- [Functional Programming](./functional/README.md) diff --git a/anti_patterns/README.md b/anti_patterns/README.md index c318b4d0..45b876ae 100644 --- a/anti_patterns/README.md +++ b/anti_patterns/README.md @@ -1,3 +1,6 @@ # Anti-patterns -TODO: add description/explanation +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. diff --git a/functional/README.md b/functional/README.md new file mode 100644 index 00000000..a8fd63eb --- /dev/null +++ b/functional/README.md @@ -0,0 +1,53 @@ +# Functional Usage of Rust + +Rust is an imperative language, but it follows many functional programming paradigms. 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. + +## Imperative + +```rust +let mut sum = 0; +for i in 1..11 { + sum += i; +} +println!("{}", sum); +``` + +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. + +| `i` | `sum` | +| --- | ----- | +| 1 | 1 | +| 2 | 3 | +| 3 | 6 | +| 4 | 10 | +| 5 | 15 | +| 6 | 21 | +| 7 | 28 | +| 8 | 36 | +| 9 | 45 | +| 10 | 55 | + +This is how most of us start out programming. We learn that a program is a set of steps. + +## Declarative + +```rust +println!("{}", (1..11).fold(0, |a, b| a + b)); +``` + +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. + +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`. + +| `a` | `b` | result | +| --- | --- | ------ | +| 0 | 1 | 1 | +| 1 | 2 | 3 | +| 3 | 3 | 6 | +| 6 | 4 | 10 | +| 10 | 5 | 15 | +| 15 | 6 | 21 | +| 21 | 7 | 28 | +| 28 | 8 | 36 | +| 36 | 9 | 45 | +| 45 | 10 | 55 | diff --git a/idioms/README.md b/idioms/README.md index 6b680191..721ced17 100644 --- a/idioms/README.md +++ b/idioms/README.md @@ -1,3 +1,9 @@ # Idioms -TODO: add description/explanation +[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used styles and patterns largely agreed upon by a community. They are guidelines. Writing idiomatic code allows other developers to understand what is happening because they are familiar with the form that it has. + +The computer understands the machine code that is generated by the compiler. The language is therefore mostly beneficial to the developer. So, since we have this abstraction layer, why not put it to good use and make it simple? + +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 kept simple rather than made complicated; therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided". + +> Code is there for humans, not computers, to understand. diff --git a/intro.md b/intro.md index 893bfa15..ba19c460 100644 --- a/intro.md +++ b/intro.md @@ -1,9 +1,21 @@ # Introduction ## Design patterns - -What are design patterns? What are idioms? Anti-patterns. +When developing programs, we have to solve many problems. A program can be viewed as a solution to a problem. It can also be viewed as a collection of solutions to many different problems. All of these solutions work together to solve a bigger problem. ## Design patterns in Rust -Why Rust is a bit special - functional elements, type system - borrow checker +There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. + +[Design patterns](patterns/README.md) are methods to solve common problems when writing software. + +[Anti-patterns](anti_patterns/README.md) are methods to solve these same common problems. + +However, while design patterns give us benefits, anti-patterns create more problems. There are some problems that we don't need to solve because [Rust rocks](rust_rocks.md)! + +[Idioms](idioms/README.md) are guidelines to follow when coding. They are social norms of the community. +You can break them, but if you do you should have a good reason for it. + +[Refactoring](refactoring/README.md) is the process by which you convert code that works, but is hard to understand, into code that works and is easy to understand. + +TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker diff --git a/patterns/README.md b/patterns/README.md index c80b4371..8b93b801 100644 --- a/patterns/README.md +++ b/patterns/README.md @@ -1,3 +1,21 @@ # Design Patterns -TODO: add description/explanation +[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 some of the culture and 'tribal knowledge' of programming in a 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. + +If overused, design patterns can add unnecessary complexity to programs. However, they are a great way to share intermediate and advanced level knowledge about a programming language. + +## Design patterns in Rust + +Rust has many very unique features. These features give us great benefit by removing whole classes of problems. For more about this, read why [Rust rocks](/rust_rocks.md)! Some of them are also patterns that are _unique_ to Rust. + +## YAGNI + +If you're not familiar with it, YAGNI is an acronym that stands for `You Aren't Going to Need It`. It's an important software design principle to apply as you write code. + +> The best code I ever wrote was code I never wrote. + +If we apply YAGNI to design patterns, we see that the features of Rust allow 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). + +TODO: Maybe include some code to illustrate the traits. diff --git a/patterns/newtype.md b/patterns/newtype.md index eb1f1b7b..d694b409 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -1,5 +1,9 @@ # Newtype +Rust has strong static types. This can be very different than what you are used to if you are coming from a loosely-typed language. Don't worry, though. Once you get used to them, you'll find the types actually make your life easier. Why? Because you are making implicit assumptions explicit. + +A really convenient application of the Rust type system is the Newtype pattern. + ## Description Use a tuple struct with a single field to make an opaque wrapper for a type. diff --git a/refactoring/README.md b/refactoring/README.md new file mode 100644 index 00000000..71d80b0d --- /dev/null +++ b/refactoring/README.md @@ -0,0 +1,15 @@ +# Refactoring + +Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. + +We can use [design patterns](patterns/README.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](anti_patterns/README.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. + +> Shortcuts make for long days. + +We can also use [idioms](idioms/README.md) to structure our code in a way that is understandable. + +## Tests + +Tests are of vital importance during refactoring. + +## Small changes From b5e755dd80e4910e7f13e6961769a5d5ad00c08e Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:22:09 +0100 Subject: [PATCH 032/217] Fix 404 (#125) --- patterns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/README.md b/patterns/README.md index 8b93b801..324a6c34 100644 --- a/patterns/README.md +++ b/patterns/README.md @@ -8,7 +8,7 @@ If overused, design patterns can add unnecessary complexity to programs. However ## Design patterns in Rust -Rust has many very unique features. These features give us great benefit by removing whole classes of problems. For more about this, read why [Rust rocks](/rust_rocks.md)! Some of them are also patterns that are _unique_ to Rust. +Rust has many very unique features. These features give us great benefit by removing whole classes of problems. Some of them are also patterns that are _unique_ to Rust. ## YAGNI From b6e5414941bb22a238e07c2e58fea0fd8f3c3692 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:40:52 +0100 Subject: [PATCH 033/217] Add doc tests to CI (#124) * rename baz() into main() and vice versa where applicable Fixes #49 --- .github/workflows/ci.yml | 21 +++++++++++++++++++-- anti_patterns/deny-warnings.md | 4 ++-- anti_patterns/deref.md | 11 ++++++++--- idioms/ctor.md | 2 +- idioms/default.md | 2 +- idioms/deref.md | 9 ++++++--- idioms/dtor-finally.md | 2 +- idioms/on-stack-dyn-dispatch.md | 6 ++++-- idioms/pass-var-to-closure.md | 4 ++++ idioms/priv-extend.md | 2 +- idioms/rustdoc-init.md | 4 ++-- idioms/temporary-mutability.md | 4 ++-- patterns/RAII.md | 27 ++++++++++++++++++--------- patterns/builder.md | 10 ++++++---- patterns/compose-structs.md | 6 +++--- patterns/fold.md | 2 +- patterns/newtype.md | 18 +++++++++++------- patterns/visitor.md | 4 ++-- 18 files changed, 92 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd33f2f1..0ce1edc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,7 @@ on: pull_request: jobs: - - test: + deploy-test: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -24,3 +23,21 @@ jobs: mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - run: mdbook build + + doc-test: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Read .env + id: mdbook-version + run: | + . ./.env + echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v1 + with: + mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' + + - run: mdbook test diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index e019c765..b19a68d2 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -55,7 +55,7 @@ without requiring a change to the code. 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: -```rust +```rust,ignore #[deny(bad-style, const-err, dead-code, @@ -84,7 +84,7 @@ Here is a list of warning lints that is (hopefully) safe to deny: In addition, the following `allow`ed lints may be a good idea to `deny`: -```rust +```rust,ignore #[deny(missing-debug-implementations, missing-docs, trivial-casts, diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index a5a69849..f037c749 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -26,11 +26,16 @@ public static void main(String[] args) { We can use the deref polymorphism anti-pattern to do so: -```rust +```rust,ignore +use std::ops::Deref; + struct Foo {} impl Foo { - fn m(&self) { ... } + fn m(&self) { + //.. + } + } struct Bar { @@ -68,7 +73,7 @@ well as `Bar`. You save a little boilerplate, e.g., -```rust +```rust,ignore impl Bar { fn m(&self) { self.f.m() diff --git a/idioms/ctor.md b/idioms/ctor.md index 7ff38bcf..17684b76 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -8,7 +8,7 @@ is to use a static `new` method to create an object. ## Example -```rust +```rust,ignore // A Rust vector, see liballoc/vec.rs pub struct Vec { buf: RawVec, diff --git a/idioms/default.md b/idioms/default.md index 5abcc2a7..45a9b7ec 100644 --- a/idioms/default.md +++ b/idioms/default.md @@ -19,7 +19,7 @@ different names, but there can only be one `Default` implementation per type. ## Example -```rust +```rust,ignore // note that we can simply auto-derive Default here. #[derive(Default)] struct MyConfiguration { diff --git a/idioms/deref.md b/idioms/deref.md index 86d67d1b..999e1c41 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -8,16 +8,19 @@ and borrowed views of data. ## Example -```rust +```rust,ignore +use std::ops::Deref; + struct Vec { - ... + data: T, + //.. } impl Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { - ... + //.. } } ``` diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index b7edf52f..3e2d2873 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -9,7 +9,7 @@ be used to run code that must be run before exit. ## Example -```rust +```rust,ignore fn bar() -> Result<(), ()> { // These don't need to be defined inside the function. struct Foo; diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index e4dc011d..e0c29a27 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -9,7 +9,9 @@ below: ## Example -```rust +```rust,ignore +std::io::File; + // These must live longer than `readable`, and thus are declared first: let (mut stdin_read, mut file_read); @@ -46,7 +48,7 @@ whole code that follows to work with both `File` or `Stdin`, with all the The code needs more moving parts than the `Box`-based version: -```rust +```rust,ignore // We still need to ascribe the type for dynamic dispatch. let readable: Box = if arg == "-" { Box::new(io::stdin()) diff --git a/idioms/pass-var-to-closure.md b/idioms/pass-var-to-closure.md index 2df610d0..4d82767d 100644 --- a/idioms/pass-var-to-closure.md +++ b/idioms/pass-var-to-closure.md @@ -14,6 +14,8 @@ Use variable rebinding in separate scope for that. Use ```rust +use std::rc::Rc; + let num1 = Rc::new(1); let num2 = Rc::new(2); let num3 = Rc::new(3); @@ -30,6 +32,8 @@ let closure = { instead of ```rust +use std::rc::Rc; + let num1 = Rc::new(1); let num2 = Rc::new(2); let num3 = Rc::new(3); diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index 492bec1e..b8d05ace 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -8,7 +8,7 @@ stability guarantees. ## Example -```rust +```rust,ignore mod a { // Public struct. pub struct S { diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 60d6c9b4..6c693757 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -11,7 +11,7 @@ Each of these methods should have examples. For example: -```rust +```rust,ignore struct Connection { name: String, stream: TcpStream, @@ -43,7 +43,7 @@ impl Connection { ## Example Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just create a wrapping dummy function which takes them as arguments: -```rust +```rust,ignore struct Connection { name: String, stream: TcpStream, diff --git a/idioms/temporary-mutability.md b/idioms/temporary-mutability.md index fff21d05..2b7bb21d 100644 --- a/idioms/temporary-mutability.md +++ b/idioms/temporary-mutability.md @@ -14,7 +14,7 @@ Say, vector must be sorted before usage. Using nested block: -```rust +```rust,ignore let data = { let mut data = get_vec(); data.sort(); @@ -26,7 +26,7 @@ let data = { Using variable rebinding: -```rust +```rust,ignore let mut data = get_vec(); data.sort(); let data = data; diff --git a/patterns/RAII.md b/patterns/RAII.md index 9da6a0d6..61875cc5 100644 --- a/patterns/RAII.md +++ b/patterns/RAII.md @@ -13,25 +13,32 @@ on the type system to ensure that access is always mediated by the guard object. Mutex guards are the classic example of this pattern from the std library (this is a simplified version of the real implementation): -```rust +```rust,ignore +use std::ops::Deref; + +struct Foo {} + struct Mutex { // We keep a reference to our data: T here. - ... + //.. } struct MutexGuard<'a, T: 'a> { data: &'a T, - ... + //.. } // Locking the mutex is explicit. impl Mutex { fn lock(&self) -> MutexGuard { // Lock the underlying OS mutex. - ... + //.. // MutexGuard keeps a reference to self - MutexGuard { data: self, ... } + MutexGuard { + data: self, + //.. + } } } @@ -39,7 +46,7 @@ impl Mutex { impl<'a, T> Drop for MutexGuard<'a, T> { fn drop(&mut self) { // Unlock the underlying OS mutex. - ... + //.. } } @@ -52,7 +59,7 @@ impl<'a, T> Deref for MutexGuard<'a, T> { } } -fn main(x: Mutex) { +fn baz(x: Mutex) { let xx = x.lock(); xx.foo(); // foo is a method on Foo. // The borrow checker ensures we can't store a reference to the underlying @@ -90,8 +97,10 @@ 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: -```rust -fn deref<'a>(&'a self) -> &'a T { ... } +```rust,ignore +fn deref<'a>(&'a self) -> &'a T { + //.. +} ``` The returned reference to the resource has the same lifetime as `self` (`'a`). diff --git a/patterns/builder.md b/patterns/builder.md index 4b6ce12d..f9366c93 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -7,18 +7,20 @@ Construct an object with calls to a builder helper. ## Example -```rust +```rust,ignore struct Foo { // Lots of complicated fields. } struct FooBuilder { // Probably lots of optional fields. - ... + //.. } impl FooBuilder { - fn new(...) -> FooBuilder { + fn new( + //.. + ) -> FooBuilder { // Set the minimally required fields of Foo. } @@ -85,7 +87,7 @@ The example takes and returns the builder by value. It is often more ergonomic borrow checker makes this work naturally. This approach has the advantage that one can write code like -``` +```rust,ignore let mut fb = FooBuilder::new(); fb.a(); fb.b(); diff --git a/patterns/compose-structs.md b/patterns/compose-structs.md index 449fdc3e..d9b9f72e 100644 --- a/patterns/compose-structs.md +++ b/patterns/compose-structs.md @@ -20,7 +20,7 @@ pattern often reveals smaller units of functionality. Here is a contrived example of where the borrow checker foils us in our plan to use a struct: -```rust +```rust,ignore struct A { f1: u32, f2: u32, @@ -30,7 +30,7 @@ struct A { fn foo(a: &mut A) -> &u32 { &a.f2 } fn bar(a: &mut A) -> u32 { a.f1 + a.f3 } -fn main(a: &mut A) { +fn baz(a: &mut A) { // x causes a to be borrowed for the rest of the function. let x = foo(a); // Borrow check error @@ -59,7 +59,7 @@ struct C { fn foo(b: &mut B) -> &u32 { &b.f2 } fn bar(c: &mut C) -> u32 { c.f1 + c.f3 } -fn main(a: &mut A) { +fn baz(a: &mut A) { let x = foo(&mut a.b); // Now it's OK! let y = bar(&mut a.c); diff --git a/patterns/fold.md b/patterns/fold.md index 4d70d4f9..6b649b82 100644 --- a/patterns/fold.md +++ b/patterns/fold.md @@ -11,7 +11,7 @@ fold in the usual sense. See the discussion below for more details. ## Example -```rust +```rust,ignore // The data we will fold, a simple AST. mod ast { pub enum Stmt { diff --git a/patterns/newtype.md b/patterns/newtype.md index d694b409..386efe50 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -11,15 +11,15 @@ This creates a new type, rather than an alias to a type (`type` items). ## Example -```rust +```rust,ignore // Some type, not necessarily in the same module or even crate. struct Foo { - ... + //.. } impl Foo { // These functions are not present on Bar. - ... + //.. } // The newtype. @@ -27,11 +27,15 @@ pub struct Bar(Foo); impl Bar { // Constructor. - pub fn new(...) -> Bar { - ... + pub fn new( + //.. + ) -> Bar { + + //.. + } - ... + //.. } fn main() { @@ -84,7 +88,7 @@ most common uses, but they can be used for other reasons: * making a type with copy semantics have move semantics, * abstraction by providing a more concrete type and thus hiding internal types, e.g., -```rust +```rust,ignore pub struct Foo(Bar); ``` diff --git a/patterns/visitor.md b/patterns/visitor.md index 604d211e..855a3e08 100644 --- a/patterns/visitor.md +++ b/patterns/visitor.md @@ -13,7 +13,7 @@ a collection of objects from the operations performed on each object. ## Example -```rust +```rust,ignore // The data we will visit mod ast { pub enum Stmt { @@ -87,7 +87,7 @@ 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, -```rust +```rust,ignore pub fn walk_expr(visitor: &mut Visitor, e: &Expr) { match *e { Expr::IntLit(_) => {}, From bc49bb4e37f98637f047ea872c73cad3cdab7f47 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:41:19 +0100 Subject: [PATCH 034/217] Fixing outdated link to rust-postgress (#121) * Fixing outdated link to rust-postgress Fixes #98 * Remove newline Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 0f74fbd4..cacab546 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). * [Concatenating strings with `format!`](idioms/concat-format.md) * [Privacy for extensibility](idioms/priv-extend.md) * TODO stability for extensibility -* TODO trait to separate visibility of methods from visibility of data (https://github.com/sfackler/rust-postgres/blob/master/src/lib.rs#L1400) +* TODO trait to separate visibility of methods from visibility of data (https://github.com/sfackler/rust-postgres/blob/v0.9.6/src/lib.rs#L1400) * [Collections are smart pointers](idioms/deref.md) * TODO leak amplification ("Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration") * [Finalisation in destructors](idioms/dtor-finally.md) @@ -93,5 +93,3 @@ If you want to build it locally you can run one of these two commands in the roo Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output to be sure) and reloads the browser when a change occurs. - - From 7fc0ae1cba42548c15315c9b75397dd66f14a54e Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:56:39 +0100 Subject: [PATCH 035/217] Adding Nick Camerons talk at PDXRust 2016 to additional resources section (#102) * Adding Nick Camerons talk at PDXRust 2016 Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- SUMMARY.md | 2 ++ additional_resources.md | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 additional_resources.md diff --git a/SUMMARY.md b/SUMMARY.md index a8de1896..ea3280b9 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -33,3 +33,5 @@ - [Deref Polymorphism](./anti_patterns/deref.md) - [Functional Programming](./functional/README.md) + +- [Additional Resources](./additional_resources.md) diff --git a/additional_resources.md b/additional_resources.md new file mode 100644 index 00000000..da6feac9 --- /dev/null +++ b/additional_resources.md @@ -0,0 +1,7 @@ +# Additional resources + +A collection of complementary helpful content + +## Talks + +- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by Nick Cameron at the PDRust (2016) From d89b51f4d8940e72454e2fd7bdd8d93c431d5c03 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:58:40 +0100 Subject: [PATCH 036/217] Adding Contribution guide (#123) * Add statement for non working examples to template * Adding contribution guide * Add statement about wayback machine --- CONTRIBUTING.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 17 +++++++++-------- template.md | 9 +++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..1be927d8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contributing + +## Discssion board + +If you have a question or an idea regarding certain content but you want to have feedback of fellow community members +and you think it may not be appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). + + +## Writing a new article + +Before writing a new article please check our [issues](https://github.com/rust-unofficial/patterns/issues) and +the [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) if there are existing issues or someone +is working on that topic. + +If you don't find an issue regarding your topic and you are sure it is not more feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) +please open a new issue, so we can discuss about the ideas and future content of the article together and maybe +give some feedback/input on it. + +When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) into the +appropriate directory and start editing it. You may not want to fill out every section and remove it or you might want to add extra sections. + +Consider writing your article in a way that has a low barrier of entry so also [Rustlings](https://github.com/rust-lang/rustlings) can follow +and understand the thought process behind it. So we can encourage people to use these patterns early on. + +We encourage you to write idiomatic Rust code that builds in the [playground](https://play.rust-lang.org/). + +If you use links to blogposts or in general content that is not to be sure existing in a few years (e.g. pdfs) please take a snapshot +with the [Wayback Machine](https://web.archive.org/) and use the link to that snapshot in your article. + +Don't forget to add your new article to the `SUMMARY.md` to let it be rendered to the book. + +Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). + + + +## Creating a Pull Request + +"Release early and often!" also applies to pull requests! + +Once your article has some visible work, create a `[WIP]` draft pull request and give it a description of what you did or want to do. +Early reviews of the community are not meant as an offense but to give feedback. + +A good principle: "Work together, share ideas, teach others." + +### Important Note + +Please **don't force push** your branch to keep commit history and make it easier of us to see changes between reviews. + +Make sure to `Allow edits of maintainers` (under the text box) in the PR so people can actually collaborate on things or fix smaller issues themselves. diff --git a/README.md b/README.md index cacab546..0bc87f06 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). [Introduction](intro.md) + ### Idioms * [Constructor](idioms/ctor.md) @@ -68,16 +69,11 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). ## Contributing -Contributions are very welcome! - -You should start with [the template](template.md). Copy it into the appropriate -directory, edit it, and submit a PR. You might not want every section, and you -might want to add extra sections. +You are missing content in this repository that can be helpful for others and you are eager to explain it? +Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. -We suggest leaving a comment on the [issue tracker](https://github.com/rust-unofficial/patterns/issues) -so that other people don't start working on the same topic. +We suggest reading our [Contribution guide](./CONTRIBUTION.md) to get more information on how it works. -Correction and elaboration PRs are very welcome. ## Building with mdbook @@ -93,3 +89,8 @@ If you want to build it locally you can run one of these two commands in the roo Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output to be sure) and reloads the browser when a change occurs. + + +## License + +This content of this repository is licensed under **MPL-2.0**; see [LICENSE](./LICENSE). diff --git a/template.md b/template.md index 48982006..f8e4ff3e 100644 --- a/template.md +++ b/template.md @@ -12,6 +12,15 @@ A short, prose description of the pattern. // liberally. ``` +When writing examples, please try to make them compile. This allows us to test +them. If you fail to write an example that is both complete and readable, +please at least mark your example code with `ignore` as in here: + +```rust,ignore +// A non-runnable example of the pattern in action, should be mostly code, commented +// liberally. +``` + ## Motivation From 721a6dff862805129a818b157967112691a472bf Mon Sep 17 00:00:00 2001 From: llogiq Date: Sat, 2 Jan 2021 13:03:36 +0100 Subject: [PATCH 037/217] Added information on --cap-lints to deny-warnings antipattern (#58) * added information on --cap-lints to deny-warnings antipattern Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- anti_patterns/deny-warnings.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index b19a68d2..7e4abf5b 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -36,7 +36,10 @@ All this conspires to potentially break the build whenever something changes. Furthermore, crates that supply additional lints (e.g. [rust-clippy]) can no longer be used unless the annotation is removed. This is mitigated with -[--cap-lints]. +[--cap-lints]. The `--cap-lints=warn` command line argument, turns all `deny` +lint errors into warnings. But be aware that `forbid` lints are stronger than +`deny` hence the 'forbid' level cannot be overridden to be anything lower than +an error. As a result `forbid` lints will still stop compilation. ## Alternatives @@ -45,7 +48,7 @@ setting from the code, and second, we can name the lints we want to deny explicitly. The following command line will build with all warnings set to `deny`: - + ```RUSTFLAGS="-D warnings" cargo build``` This can be done by any individual developer (or be set in a CI tool like From 9f15f69043a5218b98c13ee24ada2ce9688938fd Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 13:04:23 +0100 Subject: [PATCH 038/217] Fix typo in filename (#127) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bc87f06..791fdcd6 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). You are missing content in this repository that can be helpful for others and you are eager to explain it? Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. -We suggest reading our [Contribution guide](./CONTRIBUTION.md) to get more information on how it works. +We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how it works. ## Building with mdbook From 5846281ee4c3cc437f6fedef63e360dc1d48a539 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 13:32:30 +0100 Subject: [PATCH 039/217] Remove reference to rust_rocks.md (#128) * Remove reference to rust_rocks.md Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intro.md b/intro.md index ba19c460..21b85d63 100644 --- a/intro.md +++ b/intro.md @@ -11,7 +11,7 @@ There are many problems that share the same form. Due to the fact that Rust is n [Anti-patterns](anti_patterns/README.md) are methods to solve these same common problems. -However, while design patterns give us benefits, anti-patterns create more problems. There are some problems that we don't need to solve because [Rust rocks](rust_rocks.md)! +However, while design patterns give us benefits, anti-patterns create more problems. [Idioms](idioms/README.md) are guidelines to follow when coding. They are social norms of the community. You can break them, but if you do you should have a good reason for it. From c2b307fa9ba48d8fecaff036ba5a3b0945cbc36f Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 14:07:14 +0100 Subject: [PATCH 040/217] Fixing links (#129) --- intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intro.md b/intro.md index 21b85d63..632d2f15 100644 --- a/intro.md +++ b/intro.md @@ -7,15 +7,15 @@ When developing programs, we have to solve many problems. A program can be viewe There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. -[Design patterns](patterns/README.md) are methods to solve common problems when writing software. +[Design patterns](./patterns/README.md) are methods to solve common problems when writing software. -[Anti-patterns](anti_patterns/README.md) are methods to solve these same common problems. +[Anti-patterns](./anti_patterns/README.md) are methods to solve these same common problems. However, while design patterns give us benefits, anti-patterns create more problems. -[Idioms](idioms/README.md) are guidelines to follow when coding. They are social norms of the community. +[Idioms](./idioms/README.md) are guidelines to follow when coding. They are social norms of the community. You can break them, but if you do you should have a good reason for it. -[Refactoring](refactoring/README.md) is the process by which you convert code that works, but is hard to understand, into code that works and is easy to understand. +[Refactoring](./refactoring/README.md) is the process by which you convert code that works, but is hard to understand, into code that works and is easy to understand. TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker From d55a89ded41c7bf19e284411bff37faef831a7dd Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 14:29:07 +0100 Subject: [PATCH 041/217] Add direct links due to #130 (#131) --- intro.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/intro.md b/intro.md index 632d2f15..ffc950a4 100644 --- a/intro.md +++ b/intro.md @@ -7,15 +7,13 @@ When developing programs, we have to solve many problems. A program can be viewe There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. -[Design patterns](./patterns/README.md) are methods to solve common problems when writing software. +[Design patterns](https://rust-unofficial.github.io/patterns/patterns/index.html) are methods to solve common problems when writing software. -[Anti-patterns](./anti_patterns/README.md) are methods to solve these same common problems. +[Anti-patterns](https://rust-unofficial.github.io/patterns/anti_patterns/index.html) are methods to solve these same common problems. However, while design patterns give us benefits, anti-patterns create more problems. -[Idioms](./idioms/README.md) are guidelines to follow when coding. They are social norms of the community. +[Idioms](https://rust-unofficial.github.io/patterns/idioms/index.html) are guidelines to follow when coding. They are social norms of the community. You can break them, but if you do you should have a good reason for it. -[Refactoring](./refactoring/README.md) is the process by which you convert code that works, but is hard to understand, into code that works and is easy to understand. - TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker From ff9298a6076c901fb5f9234cc588f10969e96ce9 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 2 Jan 2021 18:28:25 +0100 Subject: [PATCH 042/217] Remove Entry API due to being a template copy (#133) --- SUMMARY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index ea3280b9..850b495b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -19,7 +19,6 @@ - [Design Patterns](./patterns/README.md) - [Builder](./patterns/builder.md) - [Compose Structs](./patterns/compose-structs.md) - - [Entry API](./patterns/entry.md) - [Fold](./patterns/fold.md) - [Late Bound Bounds](./patterns/late-bounds.md) - [Newtype](./patterns/newtype.md) From cae562b31119e400d00e14342b79829ca75367ff Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 03:26:01 +0100 Subject: [PATCH 043/217] Remove incomplete phrase (#138) --- idioms/on-stack-dyn-dispatch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index e0c29a27..084d971c 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -42,7 +42,7 @@ for it. 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`, with all the +whole code that follows to work with both `File` or `Stdin`. ## Disadvantages From 2bc728d1d369052916a3168b00b96a027eaab9f3 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 3 Jan 2021 03:43:04 +0100 Subject: [PATCH 044/217] Marking Motivation in Compose Structs as TODO (#140) --- patterns/compose-structs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/compose-structs.md b/patterns/compose-structs.md index d9b9f72e..874bda02 100644 --- a/patterns/compose-structs.md +++ b/patterns/compose-structs.md @@ -69,7 +69,7 @@ fn baz(a: &mut A) { ## Motivation -Why and where you should use the pattern +TODO Why and where you should use the pattern ## Advantages From eefd9ef291cfbe1e95bb4265f5a3d45372434987 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 03:55:15 +0100 Subject: [PATCH 045/217] Add explanation how to test the book to contributing (#139) --- CONTRIBUTING.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1be927d8..26a26263 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,10 @@ # Contributing -## Discssion board +## Discussion board If you have a question or an idea regarding certain content but you want to have feedback of fellow community members and you think it may not be appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). - ## Writing a new article Before writing a new article please check our [issues](https://github.com/rust-unofficial/patterns/issues) and @@ -29,9 +28,7 @@ with the [Wayback Machine](https://web.archive.org/) and use the link to that sn Don't forget to add your new article to the `SUMMARY.md` to let it be rendered to the book. -Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). - - +Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). ## Creating a Pull Request @@ -42,6 +39,11 @@ Early reviews of the community are not meant as an offense but to give feedback. A good principle: "Work together, share ideas, teach others." +### Test the book locally before submitting + +Before submitting the PR launch the commands `mdbook build` to make sure that the book builds and `mdbook test` to make sure that +code examples are correct. + ### Important Note Please **don't force push** your branch to keep commit history and make it easier of us to see changes between reviews. From bff48fae2cb02cfbdba1731239ec470e1f525735 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 3 Jan 2021 05:35:13 +0100 Subject: [PATCH 046/217] Remove templated late bounds from summary (#142) --- SUMMARY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 850b495b..a04079c1 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -20,7 +20,6 @@ - [Builder](./patterns/builder.md) - [Compose Structs](./patterns/compose-structs.md) - [Fold](./patterns/fold.md) - - [Late Bound Bounds](./patterns/late-bounds.md) - [Newtype](./patterns/newtype.md) - [RAII Guards](./patterns/RAII.md) - [Prefer Small Crates](./patterns/small-crates.md) From acef005895b227aeaf05d84ab6b08db287eb2dc7 Mon Sep 17 00:00:00 2001 From: brandondong Date: Sat, 2 Jan 2021 23:34:16 -0800 Subject: [PATCH 047/217] Update compose structs compile error example for NLL (#136) --- patterns/compose-structs.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/patterns/compose-structs.md b/patterns/compose-structs.md index 874bda02..232d0014 100644 --- a/patterns/compose-structs.md +++ b/patterns/compose-structs.md @@ -20,7 +20,7 @@ pattern often reveals smaller units of functionality. Here is a contrived example of where the borrow checker foils us in our plan to use a struct: -```rust,ignore +```rust struct A { f1: u32, f2: u32, @@ -31,10 +31,11 @@ fn foo(a: &mut A) -> &u32 { &a.f2 } fn bar(a: &mut A) -> u32 { a.f1 + a.f3 } fn baz(a: &mut A) { - // x causes a to be borrowed for the rest of the function. + // The later usage of x causes a to be borrowed for the rest of the function. let x = foo(a); - // Borrow check error - let y = bar(a); //~ ERROR: cannot borrow `*a` as mutable more than once at a time + // Borrow checker error: + // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once at a time + println!("{}", x); } ``` @@ -63,6 +64,7 @@ fn baz(a: &mut A) { let x = foo(&mut a.b); // Now it's OK! let y = bar(&mut a.c); + println!("{}", x); } ``` From e333d15258d55ce76ef12bf4360eca9bfad3932e Mon Sep 17 00:00:00 2001 From: Ovidiu Curcan Date: Sun, 3 Jan 2021 08:39:53 +0100 Subject: [PATCH 048/217] Fix on-stack dispatch example (#137) A `char` can't be used as a path. You already use the correct `"-"` in the "Disadvantages" example. Remove `ignore` for the example block --- idioms/on-stack-dyn-dispatch.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index 084d971c..64155ec0 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -9,14 +9,18 @@ below: ## Example -```rust,ignore -std::io::File; +```rust +use std::io; +use std::fs; + +# fn main() -> Result<(), Box> { +# let arg = "-"; // These must live longer than `readable`, and thus are declared first: let (mut stdin_read, mut file_read); // We need to ascribe the type to get dynamic dispatch. -let readable: &mut dyn io::Read = if arg == '-' { +let readable: &mut dyn io::Read = if arg == "-" { stdin_read = io::stdin(); &mut stdin_read } else { @@ -25,6 +29,9 @@ let readable: &mut dyn io::Read = if arg == '-' { }; // Read from `readable` here. + +# Ok(()) +# } ``` ## Motivation From 4017a73d6276b79c2f1541b2e775b5897d2b654d Mon Sep 17 00:00:00 2001 From: Riley Shea Date: Sun, 3 Jan 2021 02:44:31 -0500 Subject: [PATCH 049/217] Fix default idiom example (#134) Before this change, the example code doesn't run on the current rust stable release(1.49). This is because `Path` inherently has a u8 that requires the sized trait which requires either statics or replacing Path with PathBuf. After this change, the example code will run "as-is" without warnings or errors. --- idioms/default.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/idioms/default.md b/idioms/default.md index 45a9b7ec..4717a029 100644 --- a/idioms/default.md +++ b/idioms/default.md @@ -19,14 +19,16 @@ different names, but there can only be one `Default` implementation per type. ## Example -```rust,ignore +```rust +use std::{path::PathBuf, time::Duration}; + // note that we can simply auto-derive Default here. -#[derive(Default)] +#[derive(Default, Debug)] struct MyConfiguration { // Option defaults to None - output: Option, + output: Option, // Vecs default to empty vector - search_path: Vec, + search_path: Vec, // Duration defaults to zero time timeout: Duration, // bool defaults to false @@ -40,7 +42,9 @@ impl MyConfiguration { fn main() { // construct a new instance with default values let mut conf = MyConfiguration::default(); - // do somthing with conf here + // do something with conf here + conf.check = true; + println!("conf = {:#?}", conf); } ``` From a46baf38b3014d421b3f588dcae1602bb61dd162 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 10:42:20 +0100 Subject: [PATCH 050/217] README: remove Table of Contents (#144) It is a duplicate of SUMMARY.md --- README.md | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 791fdcd6..20003611 100644 --- a/README.md +++ b/README.md @@ -4,46 +4,24 @@ An open source book about design patterns and idioms in the Rust programming language that you can read [here](https://rust-unofficial.github.io/patterns/). -## Contents - -[Introduction](intro.md) - +## TODOs ### Idioms -* [Constructor](idioms/ctor.md) -* [Concatenating strings with `format!`](idioms/concat-format.md) -* [Privacy for extensibility](idioms/priv-extend.md) * TODO stability for extensibility * TODO trait to separate visibility of methods from visibility of data (https://github.com/sfackler/rust-postgres/blob/v0.9.6/src/lib.rs#L1400) -* [Collections are smart pointers](idioms/deref.md) * TODO leak amplification ("Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration") -* [Finalisation in destructors](idioms/dtor-finally.md) * TODO interior mutability - UnsafeCell, Cell, RefCell -* [Iterating over an `Option`](idioms/option-iter.md) -* [`Default` trait](idioms/default.md) -* [Pass variables to closure](idioms/pass-var-to-closure.md) -* [`mem::replace(_)` to avoid needless clones](idioms/mem-replace.md) -* [Temporary mutability](idioms/temporary-mutability.md) -* [On-Stack Dynamic Dispatch](idioms/on-stack-dyn-dispatch.md) * TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) -* [Easy doc initialization](idioms/rustdoc-init.md) ### Design patterns -* [Builder](patterns/builder.md) -* [RAII guards](patterns/RAII.md) -* [Newtype](patterns/newtype.md) * TODO iterators (to safely avoid bounds checks) * TODO closures and lifetimes (coupling to lifetime) * TODO platform-specific sub-modules (https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md#platform-specific-opt-in) * TODO Module organisation (by looking at examples such as Rusts `libstd`, and how it integrated into the Rusts source code, lessons can be learned about ergonomic project management and API design. Closely assosciated with platform-specific sub-modules) -* [Entry API](patterns/entry.md) (TODO Currently just a boilerplate) -* [Visitor](patterns/visitor.md) -* [Fold](patterns/fold.md) -* [Prefer small crates](patterns/small-crates.md) -* [Contain unsafety in small modules](patterns/unsafe-mods.md) +* [Entry API](patterns/entry.md) (Currently just a boilerplate) * TODO extension traits * TODO destructor bombs (ensure linear typing dynamically, e.g., https://github.com/Munksgaard/session-types/commit/0f25ccb7c3bc9f65fa8eaf538233e8fe344a189a) * TODO convertible to Foo trait for more generic generics (e.g., http://static.rust-lang.org/doc/master/std/fs/struct.File.html#method.open) @@ -52,19 +30,16 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). * TODO composition of structs to please the borrow checker * TODO `Error` traits and `Result` forwarding * TODO graphs -* [Compose structs together for better borrowing](patterns/compose-structs.md) ### Anti-patterns * TODO thread + catch_panic for exceptions * TODO Clone to satisfy the borrow checker -* [Deref polymorphism](anti_patterns/deref.md) * TODO Matching all fields of a struct (back compat) * TODO wildcard matches * TODO taking an enum rather than having multiple functions * TODO `unwrap()`ing every `Result` instead of forwarding it -* [`#[deny(warnings)]`](anti_patterns/deny-warnings.md) ## Contributing From 344b5b8fbd95ded6dd3c369e38f5c7d72c896157 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 10:43:49 +0100 Subject: [PATCH 051/217] Fix internal links (#143) * Rename Readme to index to fix internal book links Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- SUMMARY.md | 8 ++++---- anti_patterns/{README.md => index.md} | 0 functional/{README.md => index.md} | 0 idioms/{README.md => index.md} | 0 intro.md | 6 +++--- patterns/{README.md => index.md} | 0 refactoring/README.md | 15 --------------- refactoring/index.md | 15 +++++++++++++++ 8 files changed, 22 insertions(+), 22 deletions(-) rename anti_patterns/{README.md => index.md} (100%) rename functional/{README.md => index.md} (100%) rename idioms/{README.md => index.md} (100%) rename patterns/{README.md => index.md} (100%) delete mode 100644 refactoring/README.md create mode 100644 refactoring/index.md diff --git a/SUMMARY.md b/SUMMARY.md index a04079c1..488377fa 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -2,7 +2,7 @@ - [Introduction](./intro.md) -- [Idioms](./idioms/README.md) +- [Idioms](./idioms/index.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) - [Constructor](./idioms/ctor.md) - [The `Default` Trait](./idioms/default.md) @@ -16,7 +16,7 @@ - [Easy doc initialization](./idioms/rustdoc-init.md) - [Temporary mutability](./idioms/temporary-mutability.md) -- [Design Patterns](./patterns/README.md) +- [Design Patterns](./patterns/index.md) - [Builder](./patterns/builder.md) - [Compose Structs](./patterns/compose-structs.md) - [Fold](./patterns/fold.md) @@ -26,10 +26,10 @@ - [Contain unsafety in small modules](./patterns/unsafe-mods.md) - [Visitor](./patterns/visitor.md) -- [Anti-patterns](./anti_patterns/README.md) +- [Anti-patterns](./anti_patterns/index.md) - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) - [Deref Polymorphism](./anti_patterns/deref.md) -- [Functional Programming](./functional/README.md) +- [Functional Programming](./functional/index.md) - [Additional Resources](./additional_resources.md) diff --git a/anti_patterns/README.md b/anti_patterns/index.md similarity index 100% rename from anti_patterns/README.md rename to anti_patterns/index.md diff --git a/functional/README.md b/functional/index.md similarity index 100% rename from functional/README.md rename to functional/index.md diff --git a/idioms/README.md b/idioms/index.md similarity index 100% rename from idioms/README.md rename to idioms/index.md diff --git a/intro.md b/intro.md index ffc950a4..59728b48 100644 --- a/intro.md +++ b/intro.md @@ -7,13 +7,13 @@ When developing programs, we have to solve many problems. A program can be viewe There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. -[Design patterns](https://rust-unofficial.github.io/patterns/patterns/index.html) are methods to solve common problems when writing software. +[Design patterns](./patterns/index.md) are methods to solve common problems when writing software. -[Anti-patterns](https://rust-unofficial.github.io/patterns/anti_patterns/index.html) are methods to solve these same common problems. +[Anti-patterns](./anti_patterns/index.md) are methods to solve these same common problems. However, while design patterns give us benefits, anti-patterns create more problems. -[Idioms](https://rust-unofficial.github.io/patterns/idioms/index.html) are guidelines to follow when coding. They are social norms of the community. +[Idioms](./idioms/index.md) are guidelines to follow when coding. They are social norms of the community. You can break them, but if you do you should have a good reason for it. TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker diff --git a/patterns/README.md b/patterns/index.md similarity index 100% rename from patterns/README.md rename to patterns/index.md diff --git a/refactoring/README.md b/refactoring/README.md deleted file mode 100644 index 71d80b0d..00000000 --- a/refactoring/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Refactoring - -Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. - -We can use [design patterns](patterns/README.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](anti_patterns/README.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. - -> Shortcuts make for long days. - -We can also use [idioms](idioms/README.md) to structure our code in a way that is understandable. - -## Tests - -Tests are of vital importance during refactoring. - -## Small changes diff --git a/refactoring/index.md b/refactoring/index.md new file mode 100644 index 00000000..52f16086 --- /dev/null +++ b/refactoring/index.md @@ -0,0 +1,15 @@ +# Refactoring + +Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. + +We can use [design patterns](patterns/index.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. + +> Shortcuts make for long days. + +We can also use [idioms](idioms/index.md) to structure our code in a way that is understandable. + +## Tests + +Tests are of vital importance during refactoring. + +## Small changes From 6bab5f3f467ae571d67372c2e1530e23525dd691 Mon Sep 17 00:00:00 2001 From: Thomas Gotwig Date: Sun, 3 Jan 2021 11:35:19 +0100 Subject: [PATCH 052/217] Make builder pattern more practical (#90) --- patterns/builder.md | 48 ++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/patterns/builder.md b/patterns/builder.md index f9366c93..b79725ab 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -2,48 +2,52 @@ ## Description -Construct an object with calls to a builder helper. - +Construct an object with calls to a builder helper. ## Example -```rust,ignore -struct Foo { +```rust +#[derive(Debug, PartialEq)] +pub struct Foo { // Lots of complicated fields. + bar: String, } -struct FooBuilder { +pub struct FooBuilder { // Probably lots of optional fields. - //.. + bar: String, } impl FooBuilder { - fn new( - //.. - ) -> FooBuilder { + pub fn new(/* ... */) -> FooBuilder { // Set the minimally required fields of Foo. + FooBuilder { + bar: String::from("X"), + } } - fn named(mut self, name: &str) -> FooBuilder { + pub fn name(mut self, bar: String) -> FooBuilder { // Set the name on the builder itself, and return the builder by value. + self.bar = bar; + self } - // More methods that take `mut self` and return `FooBuilder` setting up - // various aspects of a Foo. - ... - // If we can get away with not consuming the Builder here, that is an - // advantage. It means we can use the builder as a template for constructing - // many Foos. - fn finish(&self) -> Foo { + // advantage. It means we can use the FooBuilder as a template for constructing many Foos. + pub fn build(self) -> Foo { // Create a Foo from the FooBuilder, applying all settings in FooBuilder to Foo. + Foo { bar: self.bar } } } -fn main() { - let f = FooBuilder::new().named("Bar").with_attribute(...).finish(); +#[test] +fn builder_test() { + let foo = Foo { + bar: String::from("Y"), + }; + let foo_from_builder: Foo = FooBuilder::new().name(String::from("Y")).build(); + assert_eq!(foo, foo_from_builder); } - ``` @@ -91,10 +95,10 @@ one can write code like let mut fb = FooBuilder::new(); fb.a(); fb.b(); -let f = fb.finish(); +let f = fb.build(); ``` -as well as the `FooBuilder::new().a().b().finish()` style. +as well as the `FooBuilder::new().a().b().build()` style. ## See also From 450bf218dcf6db9bc1fc617e6e4bab767ce2b29a Mon Sep 17 00:00:00 2001 From: Maximilian Goisser Date: Sun, 3 Jan 2021 12:57:50 +0100 Subject: [PATCH 053/217] Add link to derive_more for newtypes (#147) --- patterns/newtype.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/patterns/newtype.md b/patterns/newtype.md index 386efe50..e6ca7f9d 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -102,3 +102,5 @@ Here, `Bar` might be some public, generic type and `T1` and `T2` are some intern [Newtypes in Haskell](https://wiki.haskell.org/Newtype) [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) + +[derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. From 991ab68d12cbd3f21a7d3403237535b5f8f09d59 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 14:16:33 +0100 Subject: [PATCH 054/217] Newtype: Convert to list (#148) --- patterns/newtype.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/patterns/newtype.md b/patterns/newtype.md index e6ca7f9d..65789752 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -97,10 +97,7 @@ Here, `Bar` might be some public, generic type and `T1` and `T2` are some intern ## See also -[Newtypes in the style guide](https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html). - -[Newtypes in Haskell](https://wiki.haskell.org/Newtype) - -[Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) - -[derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. +- [Newtypes in the style guide](https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html) +- [Newtypes in Haskell](https://wiki.haskell.org/Newtype) +- [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) +- [derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. From d7026aa694ae241155291fbc733f4edebdb4621a Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 14:55:00 +0100 Subject: [PATCH 055/217] Checking links in markdown files (#150) --- .github/workflows/url-check-config.json | 7 +++++++ .github/workflows/url-check-on-change.yml | 18 ++++++++++++++++++ .github/workflows/url-check-periodic.yml | 17 +++++++++++++++++ refactoring/index.md | 4 ++-- 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/url-check-config.json create mode 100644 .github/workflows/url-check-on-change.yml create mode 100644 .github/workflows/url-check-periodic.yml diff --git a/.github/workflows/url-check-config.json b/.github/workflows/url-check-config.json new file mode 100644 index 00000000..dd50607f --- /dev/null +++ b/.github/workflows/url-check-config.json @@ -0,0 +1,7 @@ +{ + "ignorePatterns": [ + { + "pattern": "^(http|https)://crates.io/" + } + ] +} diff --git a/.github/workflows/url-check-on-change.yml b/.github/workflows/url-check-on-change.yml new file mode 100644 index 00000000..af15a537 --- /dev/null +++ b/.github/workflows/url-check-on-change.yml @@ -0,0 +1,18 @@ +name: Check Markdown links + +on: + push: + branches: [master] + pull_request: + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-verbose-mode: 'yes' + use-quiet-mode: 'yes' + config-file: '.github/workflows/url-check-config.json' + check-modified-files-only: 'yes' diff --git a/.github/workflows/url-check-periodic.yml b/.github/workflows/url-check-periodic.yml new file mode 100644 index 00000000..402609b5 --- /dev/null +++ b/.github/workflows/url-check-periodic.yml @@ -0,0 +1,17 @@ +name: Check Markdown links Periodically + +on: + schedule: + # Run everyday at 0:00 AM + - cron: "0 0 * * *" + +jobs: + markdown-link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-verbose-mode: 'yes' + use-quiet-mode: 'yes' + config-file: '.github/workflows/url-check-config.json' diff --git a/refactoring/index.md b/refactoring/index.md index 52f16086..895da44a 100644 --- a/refactoring/index.md +++ b/refactoring/index.md @@ -2,11 +2,11 @@ Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. -We can use [design patterns](patterns/index.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. +We can use [design patterns](../patterns/index.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. > Shortcuts make for long days. -We can also use [idioms](idioms/index.md) to structure our code in a way that is understandable. +We can also use [idioms](../idioms/index.md) to structure our code in a way that is understandable. ## Tests From 7ac0b4f79db2c8c769dfaea7b6ed9981fc87eef6 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 3 Jan 2021 15:03:23 +0100 Subject: [PATCH 056/217] Newtype: Add another article to See Also (#151) --- patterns/newtype.md | 1 + 1 file changed, 1 insertion(+) diff --git a/patterns/newtype.md b/patterns/newtype.md index 65789752..1589a249 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -101,3 +101,4 @@ Here, `Bar` might be some public, generic type and `T1` and `T2` are some intern - [Newtypes in Haskell](https://wiki.haskell.org/Newtype) - [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) - [derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. +- [The Newtype Pattern In Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html) From 448af714a1ec96f0d99999996d4dd89c94673ca3 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 3 Jan 2021 23:20:00 +0800 Subject: [PATCH 057/217] Table alignment in functional/index.md (#152) * Right align table in plain text version Makes the plain text version easier to read * Center alignment in mdbook/md --- functional/index.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/functional/index.md b/functional/index.md index a8fd63eb..54126bc0 100644 --- a/functional/index.md +++ b/functional/index.md @@ -15,17 +15,17 @@ println!("{}", sum); 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. | `i` | `sum` | -| --- | ----- | -| 1 | 1 | -| 2 | 3 | -| 3 | 6 | -| 4 | 10 | -| 5 | 15 | -| 6 | 21 | -| 7 | 28 | -| 8 | 36 | -| 9 | 45 | -| 10 | 55 | +|:---:|:-----:| +| 1 | 1 | +| 2 | 3 | +| 3 | 6 | +| 4 | 10 | +| 5 | 15 | +| 6 | 21 | +| 7 | 28 | +| 8 | 36 | +| 9 | 45 | +| 10 | 55 | This is how most of us start out programming. We learn that a program is a set of steps. @@ -40,14 +40,14 @@ Whoa! This is really different! What's going on here? Remember that with declara 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`. | `a` | `b` | result | -| --- | --- | ------ | -| 0 | 1 | 1 | -| 1 | 2 | 3 | -| 3 | 3 | 6 | -| 6 | 4 | 10 | -| 10 | 5 | 15 | -| 15 | 6 | 21 | -| 21 | 7 | 28 | -| 28 | 8 | 36 | -| 36 | 9 | 45 | -| 45 | 10 | 55 | +|:---:|:---:|:------:| +| 0 | 1 | 1 | +| 1 | 2 | 3 | +| 3 | 3 | 6 | +| 6 | 4 | 10 | +| 10 | 5 | 15 | +| 15 | 6 | 21 | +| 21 | 7 | 28 | +| 28 | 8 | 36 | +| 36 | 9 | 45 | +| 45 | 10 | 55 | From f8d0570103814cc824460a9178fa34a69ef6677a Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 3 Jan 2021 23:38:28 +0800 Subject: [PATCH 058/217] Link DRY to wikipedia (#154) --- refactoring/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/refactoring/index.md b/refactoring/index.md index 895da44a..71f6b091 100644 --- a/refactoring/index.md +++ b/refactoring/index.md @@ -2,7 +2,7 @@ Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. -We can use [design patterns](../patterns/index.md) to DRY up code and generalize abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. +We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. > Shortcuts make for long days. @@ -13,3 +13,5 @@ We can also use [idioms](../idioms/index.md) to structure our code in a way that Tests are of vital importance during refactoring. ## Small changes + +[DRY]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself From 1a65aadb315c1be523d2728bb3c82bca9d867d3e Mon Sep 17 00:00:00 2001 From: join3r Date: Mon, 4 Jan 2021 05:54:27 +0100 Subject: [PATCH 059/217] Fix Spelling mistake (#157) --- idioms/dtor-finally.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index 3e2d2873..87fd1f9c 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -76,7 +76,7 @@ The finaliser must be assigned into a variable, otherwise it will be destroyed immediately, rather than when it goes out of scope. The variable name must start with `_` if the variable is only used as a finaliser, otherwise the compiler will warn that the finaliser is never used. However, do not call the variable -`_` with no suffix - in that case it will be again be destroyed immediately. +`_` with no suffix - in that case it will be destroyed immediately. 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 From c2321270fa2602829f494fa9b000099c3a19ea26 Mon Sep 17 00:00:00 2001 From: Christopher Date: Mon, 4 Jan 2021 02:31:55 -0600 Subject: [PATCH 060/217] Use coercion for arguments (#29) Describe some of the reasons it is considered idiomatic to use `&str` over `&String` in most cases. Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Co-authored-by: Chris Wong Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> Co-authored-by: Ivan Tham --- SUMMARY.md | 1 + idioms/coercion-arguments.md | 117 +++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 idioms/coercion-arguments.md diff --git a/SUMMARY.md b/SUMMARY.md index 488377fa..a0f42579 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,6 +3,7 @@ - [Introduction](./intro.md) - [Idioms](./idioms/index.md) + - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) - [Constructor](./idioms/ctor.md) - [The `Default` Trait](./idioms/default.md) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md new file mode 100644 index 00000000..a38015cf --- /dev/null +++ b/idioms/coercion-arguments.md @@ -0,0 +1,117 @@ +# Use borrowed types for arguments + +## Description + +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. + +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__. E.g., `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`. + +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 `String` has a layer of indirection, so a `&String` will have two layers of indrection. +We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. + +## Example + +For this example, we will illustrate some differences for using `&String` as a function argument versus using a `&str`, but the ideas apply as well to using `&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. + +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. + +The code might look something like this: + +```rust +fn three_vowels(word: &String) -> bool { + let mut vowel_count = 0; + for c in word.chars() { + match c { + 'a' | 'e' | 'i' | 'o' | 'u' => { + vowel_count += 1; + if vowel_count >= 3 { + return true + } + } + _ => vowel_count = 0 + } + } + false +} + +fn main() { + let ferris = "Ferris".to_string(); + let curious = "Curious".to_string(); + println!("{}: {}", ferris, three_vowels(&ferris)); + println!("{}: {}", curious, three_vowels(&curious)); + + // This works fine, but the following two lines would fail: + // println!("Ferris: {}", three_vowels("Ferris")); + // println!("Curious: {}", three_vowels("Curious")); + +} +``` + +This works fine because we are passing a `&String` type as a parameter. +If we comment in the last two lines this example fails because a `&str` type will not coerce to a `&String` type. +We can fix this by simply modifying the type for our argument. + +For instance, if we change our function declaration to: + +```rust, ignore +fn three_vowels(word: &str) -> bool { +``` + +then both versions will compile and print the same output. + +```bash +Ferris: false +Curious: true +``` + +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 anways (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`. + +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 has a word that contains three consecutive vowels. +We probably should make use of the function we have already defined and simply feed in each word from the sentence. + +An example of this could look like this: + +```rust +fn three_vowels(word: &str) -> bool { + let mut vowel_count = 0; + for c in word.chars() { + match c { + 'a' | 'e' | 'i' | 'o' | 'u' => { + vowel_count += 1; + if vowel_count >= 3 { + return true + } + } + _ => vowel_count = 0 + } + } + false +} + +fn main() { + let sentence_string = + "Once upon a time, there was a friendly curious crab named Ferris".to_string(); + for word in sentence_string.split(' ') { + if three_vowels(word) { + println!("{} has three consecutive vowels!", word); + } + } +} +``` + +Running this example using our function declared with an argument type `&str` will yield + +```bash +curious has three consecutive vowels! +``` + +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 `&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. + +## See also +- [Rust Language Reference on Type Coercions](https://doc.rust-lang.org/reference/type-coercions.html) +- 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. From e6b427ce38f0ab8b5a8395642d0405cf60c20d91 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 5 Jan 2021 11:32:36 +0800 Subject: [PATCH 061/217] Use a problem as the intro for newtype pattern (#153) A problem can highlight some of the use cases of newtype pattern rather than discussing generally that rust is strongly typed. Make the user understand the need of newtype. --- patterns/newtype.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/patterns/newtype.md b/patterns/newtype.md index 1589a249..b71aa7e1 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -1,8 +1,13 @@ # Newtype -Rust has strong static types. This can be very different than what you are used to if you are coming from a loosely-typed language. Don't worry, though. Once you get used to them, you'll find the types actually make your life easier. Why? Because you are making implicit assumptions explicit. +What if in some cases we want a type to behave similar to another type or +enforce some behaviour at compile time where using only type aliases would +not be enough? -A really convenient application of the Rust type system is the Newtype pattern. +For example, if we want to create a custom `Display` implementation for `String` +due to security considerations (e.g. passwords). + +For such cases we could use the `Newtype` pattern to provide __type safety__ and __encapsulation__. ## Description @@ -97,7 +102,7 @@ Here, `Bar` might be some public, generic type and `T1` and `T2` are some intern ## See also -- [Newtypes in the style guide](https://doc.rust-lang.org/1.0.0/style/features/types/newtype.html) +- [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) - [Newtypes in Haskell](https://wiki.haskell.org/Newtype) - [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) - [derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. From 345514a3042f979207572c86057b58f4617fe2ce Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 5 Jan 2021 06:43:55 +0100 Subject: [PATCH 062/217] Updating mdbook (#162) https://blog.rust-lang.org/2021/01/04/mdbook-security-advisory.html --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 82f6f280..4de2aeff 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.4 +MDBOOK_VERSION=0.4.5 From 5f1425d7ed242f805593eb4e09e053c127694d4c Mon Sep 17 00:00:00 2001 From: Takashi Idobe Date: Tue, 5 Jan 2021 09:36:20 -0500 Subject: [PATCH 063/217] Apply markdownlint to project (#163) --- .markdownlint.yaml | 5 ++++ CONTRIBUTING.md | 10 +++---- README.md | 16 ++++-------- SUMMARY.md | 46 ++++++++++++++++----------------- anti_patterns/deref.md | 5 ---- anti_patterns/index.md | 2 +- idioms/coercion-arguments.md | 11 ++++---- idioms/concat-format.md | 2 -- idioms/ctor.md | 3 +-- idioms/deref.md | 5 ---- idioms/dtor-finally.md | 6 ----- idioms/mem-replace.md | 2 -- idioms/on-stack-dyn-dispatch.md | 2 +- idioms/pass-var-to-closure.md | 4 --- idioms/priv-extend.md | 1 - idioms/rustdoc-init.md | 9 ++++--- idioms/temporary-mutability.md | 4 --- intro.md | 9 ++++--- patterns/RAII.md | 7 +---- patterns/builder.md | 4 --- patterns/compose-structs.md | 5 ---- patterns/entry.md | 6 ----- patterns/fold.md | 3 --- patterns/index.md | 2 +- patterns/late-bounds.md | 6 ----- patterns/newtype.md | 12 +++------ patterns/visitor.md | 3 --- refactoring/index.md | 2 +- template.md | 6 ----- 29 files changed, 65 insertions(+), 133 deletions(-) create mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..b44e3861 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,5 @@ +--- +MD004: false +MD010: + code_blocks: false +MD013: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26a26263..b9d0ed54 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,24 +2,24 @@ ## Discussion board -If you have a question or an idea regarding certain content but you want to have feedback of fellow community members +If you have a question or an idea regarding certain content but you want to have feedback of fellow community members and you think it may not be appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). ## Writing a new article -Before writing a new article please check our [issues](https://github.com/rust-unofficial/patterns/issues) and +Before writing a new article please check our [issues](https://github.com/rust-unofficial/patterns/issues) and the [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) if there are existing issues or someone is working on that topic. If you don't find an issue regarding your topic and you are sure it is not more feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) please open a new issue, so we can discuss about the ideas and future content of the article together and maybe -give some feedback/input on it. +give some feedback/input on it. When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) into the appropriate directory and start editing it. You may not want to fill out every section and remove it or you might want to add extra sections. Consider writing your article in a way that has a low barrier of entry so also [Rustlings](https://github.com/rust-lang/rustlings) can follow -and understand the thought process behind it. So we can encourage people to use these patterns early on. +and understand the thought process behind it. So we can encourage people to use these patterns early on. We encourage you to write idiomatic Rust code that builds in the [playground](https://play.rust-lang.org/). @@ -35,7 +35,7 @@ Please make `Draft Pull requests` early so we can follow your progress and can g "Release early and often!" also applies to pull requests! Once your article has some visible work, create a `[WIP]` draft pull request and give it a description of what you did or want to do. -Early reviews of the community are not meant as an offense but to give feedback. +Early reviews of the community are not meant as an offense but to give feedback. A good principle: "Work together, share ideas, teach others." diff --git a/README.md b/README.md index 20003611..9956c877 100644 --- a/README.md +++ b/README.md @@ -3,35 +3,32 @@ An open source book about design patterns and idioms in the Rust programming language that you can read [here](https://rust-unofficial.github.io/patterns/). - ## TODOs ### Idioms * TODO stability for extensibility -* TODO trait to separate visibility of methods from visibility of data (https://github.com/sfackler/rust-postgres/blob/v0.9.6/src/lib.rs#L1400) +* TODO trait to separate visibility of methods from visibility of data () * TODO leak amplification ("Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration") * TODO interior mutability - UnsafeCell, Cell, RefCell * TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) - ### Design patterns * TODO iterators (to safely avoid bounds checks) * TODO closures and lifetimes (coupling to lifetime) -* TODO platform-specific sub-modules (https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md#platform-specific-opt-in) +* TODO platform-specific sub-modules () * TODO Module organisation (by looking at examples such as Rusts `libstd`, and how it integrated into the Rusts source code, lessons can be learned about ergonomic project management and API design. Closely assosciated with platform-specific sub-modules) * [Entry API](patterns/entry.md) (Currently just a boilerplate) * TODO extension traits -* TODO destructor bombs (ensure linear typing dynamically, e.g., https://github.com/Munksgaard/session-types/commit/0f25ccb7c3bc9f65fa8eaf538233e8fe344a189a) -* TODO convertible to Foo trait for more generic generics (e.g., http://static.rust-lang.org/doc/master/std/fs/struct.File.html#method.open) +* TODO destructor bombs (ensure linear typing dynamically, e.g., ) +* TODO convertible to Foo trait for more generic generics (e.g., ) * [Late bound bounds](patterns/late-bounds.md) (Currently just a boilerplate) * TODO 'shadow' borrowed version of struct - e.g., double buffering, Niko's parser generator * TODO composition of structs to please the borrow checker * TODO `Error` traits and `Result` forwarding * TODO graphs - ### Anti-patterns * TODO thread + catch_panic for exceptions @@ -41,7 +38,6 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). * TODO taking an enum rather than having multiple functions * TODO `unwrap()`ing every `Result` instead of forwarding it - ## Contributing You are missing content in this repository that can be helpful for others and you are eager to explain it? @@ -49,7 +45,6 @@ Awesome! We are always happy about new contributions (e.g. elaboration or correc We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how it works. - ## Building with mdbook This book is built with [mdbook](https://rust-lang.github.io/mdBook/). You can install it by running `cargo install mdbook`. @@ -62,10 +57,9 @@ If you want to build it locally you can run one of these two commands in the roo - `mdbook serve` - Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output + Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output to be sure) and reloads the browser when a change occurs. - ## License This content of this repository is licensed under **MPL-2.0**; see [LICENSE](./LICENSE). diff --git a/SUMMARY.md b/SUMMARY.md index a0f42579..8429b73e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,33 +3,33 @@ - [Introduction](./intro.md) - [Idioms](./idioms/index.md) - - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - - [Concatenating Strings with `format!`](./idioms/concat-format.md) - - [Constructor](./idioms/ctor.md) - - [The `Default` Trait](./idioms/default.md) - - [Collections Are Smart Pointers](./idioms/deref.md) - - [Finalisation in Destructors](./idioms/dtor-finally.md) - - [`mem::replace(_)`](./idioms/mem-replace.md) - - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) - - [Iterating over an `Option`](./idioms/option-iter.md) - - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) - - [Privacy For Extensibility](./idioms/priv-extend.md) - - [Easy doc initialization](./idioms/rustdoc-init.md) - - [Temporary mutability](./idioms/temporary-mutability.md) + - [Use borrowed types for arguments](./idioms/coercion-arguments.md) + - [Concatenating Strings with `format!`](./idioms/concat-format.md) + - [Constructor](./idioms/ctor.md) + - [The `Default` Trait](./idioms/default.md) + - [Collections Are Smart Pointers](./idioms/deref.md) + - [Finalisation in Destructors](./idioms/dtor-finally.md) + - [`mem::replace(_)`](./idioms/mem-replace.md) + - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) + - [Iterating over an `Option`](./idioms/option-iter.md) + - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) + - [Privacy For Extensibility](./idioms/priv-extend.md) + - [Easy doc initialization](./idioms/rustdoc-init.md) + - [Temporary mutability](./idioms/temporary-mutability.md) - [Design Patterns](./patterns/index.md) - - [Builder](./patterns/builder.md) - - [Compose Structs](./patterns/compose-structs.md) - - [Fold](./patterns/fold.md) - - [Newtype](./patterns/newtype.md) - - [RAII Guards](./patterns/RAII.md) - - [Prefer Small Crates](./patterns/small-crates.md) - - [Contain unsafety in small modules](./patterns/unsafe-mods.md) - - [Visitor](./patterns/visitor.md) + - [Builder](./patterns/builder.md) + - [Compose Structs](./patterns/compose-structs.md) + - [Fold](./patterns/fold.md) + - [Newtype](./patterns/newtype.md) + - [RAII Guards](./patterns/RAII.md) + - [Prefer Small Crates](./patterns/small-crates.md) + - [Contain unsafety in small modules](./patterns/unsafe-mods.md) + - [Visitor](./patterns/visitor.md) - [Anti-patterns](./anti_patterns/index.md) - - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) - - [Deref Polymorphism](./anti_patterns/deref.md) + - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) + - [Deref Polymorphism](./anti_patterns/deref.md) - [Functional Programming](./functional/index.md) diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index f037c749..832d3fa5 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -5,7 +5,6 @@ Abuse the `Deref` trait to emulate inheritance between structs, and thus reuse methods. - ## Example Sometimes we want to emulate the following common pattern from OO languages such @@ -68,7 +67,6 @@ 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`. - ## Advantages You save a little boilerplate, e.g., @@ -81,7 +79,6 @@ impl Bar { } ``` - ## Disadvantages Most importantly this is a surprising idiom - future programmers reading this in @@ -103,7 +100,6 @@ 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. - ## Discussion There is no one good alternative. Depending on the exact circumstances it might @@ -125,7 +121,6 @@ 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. - ## See also [Collections are smart pointers idiom](../idioms/deref.md). diff --git a/anti_patterns/index.md b/anti_patterns/index.md index 45b876ae..fbae8f2c 100644 --- a/anti_patterns/index.md +++ b/anti_patterns/index.md @@ -1,6 +1,6 @@ # Anti-patterns -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". +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. diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index a38015cf..b9a18a6a 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -8,7 +8,7 @@ In this way, the function will accept more input types. 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__. E.g., `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`. 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 `String` has a layer of indirection, so a `&String` will have two layers of indrection. -We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. +We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. ## Example @@ -50,8 +50,8 @@ fn main() { ``` This works fine because we are passing a `&String` type as a parameter. -If we comment in the last two lines this example fails because a `&str` type will not coerce to a `&String` type. -We can fix this by simply modifying the type for our argument. +If we comment in the last two lines this example fails because a `&str` type will not coerce to a `&String` type. +We can fix this by simply modifying the type for our argument. For instance, if we change our function declaration to: @@ -66,7 +66,7 @@ Ferris: false Curious: true ``` -But wait, that's not all! There is more to this story. +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 anways (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`. @@ -109,9 +109,10 @@ Running this example using our function declared with an argument type `&str` wi curious has three consecutive vowels! ``` -However, this example will not run when our function is declared with an argument type `&String`. +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 `&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. ## See also + - [Rust Language Reference on Type Coercions](https://doc.rust-lang.org/reference/type-coercions.html) - 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. diff --git a/idioms/concat-format.md b/idioms/concat-format.md index e4573368..372d86e5 100644 --- a/idioms/concat-format.md +++ b/idioms/concat-format.md @@ -7,7 +7,6 @@ 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. - ## Example ```rust @@ -23,7 +22,6 @@ fn say_hello(name: &str) -> String { } ``` - ## Advantages Using `format!` is usually the most succinct and readable way to combine strings. diff --git a/idioms/ctor.md b/idioms/ctor.md index 17684b76..56ff212d 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -5,7 +5,6 @@ Rust does not have constructors as a language construct. Instead, the convention is to use a static `new` method to create an object. - ## Example ```rust,ignore @@ -34,4 +33,4 @@ impl Vec { ## See also The [builder pattern](../patterns/builder.md) for constructing objects where there are multiple -configurations. +configurations. diff --git a/idioms/deref.md b/idioms/deref.md index 999e1c41..1815301f 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -5,7 +5,6 @@ Use the `Deref` trait to treat collections like smart pointers, offering owning and borrowed views of data. - ## Example ```rust,ignore @@ -40,7 +39,6 @@ must account for these semantics properly in order to give a good user experience. When implementing a data structure which owns its data, offering a borrowed view of that data allows for more flexible APIs. - ## Advantages Most methods can be implemented only for the borrowed view, they are then @@ -48,14 +46,12 @@ implicitly available for the owning view. Gives clients a choice between borrowing or taking ownership of data. - ## Disadvantages Methods and traits only available via dereferencing are not taken into account when bounds checking, so generic programming with data structures using this pattern can get complex (see the `Borrow` and `AsRef` traits, etc.). - ## Discussion Smart pointers and collections are analogous: a smart pointer points to a single @@ -76,7 +72,6 @@ implement `Deref>` where `Bar` is a dynamically sized type and Commonly, ordered collections will implement `Index` for `Range`s to provide slicing syntax. The target will be the borrowed view. - ## See also [Deref polymorphism anti-pattern](../anti_patterns/deref.md). diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index 87fd1f9c..95436fa0 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -6,7 +6,6 @@ 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 be used to run code that must be run before exit. - ## Example ```rust,ignore @@ -30,7 +29,6 @@ fn bar() -> Result<(), ()> { } ``` - ## Motivation If a function has multiple return points, then executing code on exit becomes @@ -41,13 +39,11 @@ 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. - ## Advantages Code in destructors will (nearly) always be run - copes with panics, early returns, etc. - ## Disadvantages It is not guaranteed that destructors will run. For example, if there is an @@ -62,7 +58,6 @@ debugging tricky. Requiring an object and `Drop` impl just for finalisation is heavy on boilerplate. - ## Discussion There is some subtlety about how exactly to store the object used as a @@ -90,7 +85,6 @@ that desctructors 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. - ## See also [RAII](../patterns/RAII.md). diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index e670ae7e..5f3bd50d 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -84,7 +84,6 @@ 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. - ## Advantages Look ma, no allocation! Also you may feel like Indiana Jones while doing it. @@ -107,7 +106,6 @@ However, in Rust, we have to do a little more work to do this. An owned 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. - ## See also This gets rid of the [Clone to satisfy the borrow checker] antipattern in a diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index 64155ec0..c0764589 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -83,7 +83,7 @@ Read` ## See also -* [Finalisation in destructors](dtor-finally.md) and +* [Finalisation in destructors](dtor-finally.md) and [RAII guards](../patterns/RAII.md) can benefit from tight control over lifetimes. * For conditionally filled `Option<&T>`s of (mutable) references, one can initialize an `Option` directly and use its [`.as_ref()`] method to get an diff --git a/idioms/pass-var-to-closure.md b/idioms/pass-var-to-closure.md index 4d82767d..b9b3c329 100644 --- a/idioms/pass-var-to-closure.md +++ b/idioms/pass-var-to-closure.md @@ -8,7 +8,6 @@ give it copy of some data, pass it by reference, or perform some other transform Use variable rebinding in separate scope for that. - ## Example Use @@ -45,7 +44,6 @@ let closure = move || { }; ``` - ## Advantages Copied data are grouped together with closure definition, so their purpose is more clear @@ -53,8 +51,6 @@ and they will be dropped immediately even if they are not consumed by closure. Closure uses same variable names as surrounding code whether data are copied or moved. - ## Disadvantages Additional indentation of closure body. - diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index b8d05ace..a6c77fbb 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -5,7 +5,6 @@ Use a private field to ensure that a struct is extensible without breaking stability guarantees. - ## Example ```rust,ignore diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 6c693757..89b00f4e 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -2,12 +2,13 @@ ## Description -If a struct takes significant effort to initialize, when writing docs, it can be quicker to wrap your example with a +If a struct takes significant effort to initialize, when writing docs, it can be quicker to wrap your example with a function which takes the struct as an argument. ## Motivation + Sometimes there is a struct with multiple or complicated parameters and several methods. -Each of these methods should have examples. +Each of these methods should have examples. For example: @@ -41,6 +42,7 @@ impl Connection { ``` ## Example + Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just create a wrapping dummy function which takes them as arguments: ```rust,ignore @@ -64,6 +66,7 @@ impl Connection { } } ``` + **Note** in the above example the line `assert!(response.is_ok());` will not actually run while testing because it is inside of a function which is never invoked. ## Advantages @@ -77,7 +80,7 @@ So this pattern is most useful when need `no_run`. With this, you do not need to ## Discussion -If assertions are not required this pattern works well. +If assertions are not required this pattern works well. If they are, an alternative can be to create a public method to create a dummy 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. diff --git a/idioms/temporary-mutability.md b/idioms/temporary-mutability.md index 2b7bb21d..d473a12d 100644 --- a/idioms/temporary-mutability.md +++ b/idioms/temporary-mutability.md @@ -7,7 +7,6 @@ and never modified. The intention can be made explicit by redefining the mutable It can be done either by processing data within nested block or by redefining variable. - ## Example Say, vector must be sorted before usage. @@ -34,14 +33,11 @@ let data = data; // Here `data` is immutable. ``` - ## Advantages Compiler ensures that you don't accidentally mutate data after some point. - ## Disadvantages Nested block requires additional indentation of block body. One more line to return data from block or redefine variable. - diff --git a/intro.md b/intro.md index 59728b48..9a423b44 100644 --- a/intro.md +++ b/intro.md @@ -1,19 +1,20 @@ # Introduction ## Design patterns + When developing programs, we have to solve many problems. A program can be viewed as a solution to a problem. It can also be viewed as a collection of solutions to many different problems. All of these solutions work together to solve a bigger problem. ## Design patterns in Rust -There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. +There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. [Design patterns](./patterns/index.md) are methods to solve common problems when writing software. -[Anti-patterns](./anti_patterns/index.md) are methods to solve these same common problems. +[Anti-patterns](./anti_patterns/index.md) are methods to solve these same common problems. However, while design patterns give us benefits, anti-patterns create more problems. -[Idioms](./idioms/index.md) are guidelines to follow when coding. They are social norms of the community. -You can break them, but if you do you should have a good reason for it. +[Idioms](./idioms/index.md) are guidelines to follow when coding. They are social norms of the community. +You can break them, but if you do you should have a good reason for it. TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker diff --git a/patterns/RAII.md b/patterns/RAII.md index 61875cc5..b576a80a 100644 --- a/patterns/RAII.md +++ b/patterns/RAII.md @@ -69,20 +69,17 @@ fn baz(x: Mutex) { } ``` - ## Motivation 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 this pattern can be used to prevent such errors. - ## Advantages Prevents errors where a resource is not finalised and where a resource is used after finalisation. - ## Discussion RAII is a useful pattern for ensuring resources are properly deallocated or @@ -111,8 +108,6 @@ Note that implementing `Deref` is not a core part of this pattern, it only makes using the guard object more ergonomic. Implementing a `get` method on the guard works just as well. - - ## See also [Finalisation in destructors idiom](../idioms/dtor-finally.md) @@ -120,7 +115,7 @@ works just as well. RAII is a common pattern in C++: [cppreference.com](http://en.cppreference.com/w/cpp/language/raii), [wikipedia][wikipedia]. -[wikipedia]: https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization +[wikipedia]: https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization [Style guide entry](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html) (currently just a placeholder). diff --git a/patterns/builder.md b/patterns/builder.md index b79725ab..c3612a22 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -50,13 +50,11 @@ fn builder_test() { } ``` - ## Motivation Useful when you would otherwise require many different constructors or where construction has side effects. - ## Advantages Separates methods for building from other methods. @@ -65,13 +63,11 @@ Prevents proliferation of constructors Can be used for one-liner initialisation as well as more complex construction. - ## Disadvantages More complex than creating a struct object directly, or a simple constructor function. - ## Discussion This pattern is seen more frequently in Rust (and for simpler objects) than in diff --git a/patterns/compose-structs.md b/patterns/compose-structs.md index 232d0014..47e93eac 100644 --- a/patterns/compose-structs.md +++ b/patterns/compose-structs.md @@ -14,7 +14,6 @@ behaviour. This will often lead to a better design in other ways: applying this design pattern often reveals smaller units of functionality. - ## Example Here is a contrived example of where the borrow checker foils us in our plan to @@ -68,19 +67,16 @@ fn baz(a: &mut A) { } ``` - ## Motivation TODO Why and where you should use the pattern - ## Advantages Lets you work around limitations in the borrow checker. Often produces a better design. - ## Disadvantages Leads to more verbose code. @@ -89,7 +85,6 @@ 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. - ## Discussion This pattern is not required in languages that don't have a borrow checker, so diff --git a/patterns/entry.md b/patterns/entry.md index 4e924370..b06a07e5 100644 --- a/patterns/entry.md +++ b/patterns/entry.md @@ -4,7 +4,6 @@ A short, prose description of the pattern. - ## Example ```rust @@ -12,27 +11,22 @@ A short, prose description of the pattern. // liberally. ``` - ## Motivation Why and where you should use the pattern - ## Advantages Good things about this pattern. - ## Disadvantages Bad things about this pattern. Possible contraindications. - ## Discussion TODO vs insert_or_update etc. - ## See also [RFC](https://github.com/rust-lang/rfcs/blob/master/text/0216-collection-views.md) diff --git a/patterns/fold.md b/patterns/fold.md index 6b649b82..5b91bf7a 100644 --- a/patterns/fold.md +++ b/patterns/fold.md @@ -70,7 +70,6 @@ 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). - ## Motivation It is common to want to map a data structure by performing some operation on @@ -83,7 +82,6 @@ appropriate. Like the visitor pattern, the fold pattern allows us to separate traversal of a data structure from the operations performed to each node. - ## Discussion Mapping data structures in this fashion is common in functional languages. In OO @@ -108,7 +106,6 @@ 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. - ## See also Iterators have a `fold` method, however this folds a data structure into a diff --git a/patterns/index.md b/patterns/index.md index 324a6c34..eada5b8d 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -1,6 +1,6 @@ # Design Patterns -[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](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 some of the culture and 'tribal knowledge' of programming in a 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. diff --git a/patterns/late-bounds.md b/patterns/late-bounds.md index 8c91ef3c..fe5ebe79 100644 --- a/patterns/late-bounds.md +++ b/patterns/late-bounds.md @@ -4,7 +4,6 @@ TODO late binding of bounds for better APIs (i.e., Mutex's don't require Send) - ## Example ```rust @@ -12,29 +11,24 @@ TODO late binding of bounds for better APIs (i.e., Mutex's don't require Send) // liberally. ``` - ## Motivation Why and where you should use the pattern - ## Advantages Good things about this pattern. - ## Disadvantages Bad things about this pattern. Possible contraindications. - ## Discussion A deeper discussion about this pattern. You might want to cover how this is done in other languages, alternative approaches, why this is particularly nice in Rust, etc. - ## See also Related patterns (link to the pattern file). Versions of this pattern in other diff --git a/patterns/newtype.md b/patterns/newtype.md index b71aa7e1..7668222a 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -1,10 +1,10 @@ # Newtype -What if in some cases we want a type to behave similar to another type or -enforce some behaviour at compile time where using only type aliases would -not be enough? +What if in some cases we want a type to behave similar to another type or +enforce some behaviour at compile time where using only type aliases would +not be enough? -For example, if we want to create a custom `Display` implementation for `String` +For example, if we want to create a custom `Display` implementation for `String` due to security considerations (e.g. passwords). For such cases we could use the `Newtype` pattern to provide __type safety__ and __encapsulation__. @@ -52,7 +52,6 @@ fn main() { } ``` - ## Motivation The primary motivation for newtypes is abstraction. It allows you to share @@ -63,7 +62,6 @@ API, it allows you to change implementation backwards compatibly. Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give distinguishable `Miles` and `Kms`. - ## Advantages The wrapped and wrapper types are not type compatible (as opposed to using @@ -83,7 +81,6 @@ 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. - ## Discussion Newtypes are very common in Rust code. Abstraction or representing units are the @@ -99,7 +96,6 @@ pub struct Foo(Bar); Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. - ## See also - [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) diff --git a/patterns/visitor.md b/patterns/visitor.md index 855a3e08..9f5de670 100644 --- a/patterns/visitor.md +++ b/patterns/visitor.md @@ -10,7 +10,6 @@ behaviour). Furthermore, the visitor pattern allows separating the traversal of a collection of objects from the operations performed on each object. - ## Example ```rust,ignore @@ -70,7 +69,6 @@ impl Visitor for Interpreter { One could implement further visitors, for example a type checker, without having to modify the AST data. - ## Motivation The visitor pattern is useful anywhere that you want to apply an algorithm to @@ -78,7 +76,6 @@ 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. - ## Discussion It is common for the `visit_*` methods to return void (as opposed to in the diff --git a/refactoring/index.md b/refactoring/index.md index 71f6b091..d5490224 100644 --- a/refactoring/index.md +++ b/refactoring/index.md @@ -6,7 +6,7 @@ We can use [design patterns](../patterns/index.md) to [DRY] up code and generali > Shortcuts make for long days. -We can also use [idioms](../idioms/index.md) to structure our code in a way that is understandable. +We can also use [idioms](../idioms/index.md) to structure our code in a way that is understandable. ## Tests diff --git a/template.md b/template.md index f8e4ff3e..f5f65015 100644 --- a/template.md +++ b/template.md @@ -4,7 +4,6 @@ A short, prose description of the pattern. - ## Example ```rust @@ -21,29 +20,24 @@ please at least mark your example code with `ignore` as in here: // liberally. ``` - ## Motivation Why and where you should use the pattern - ## Advantages Good things about this pattern. - ## Disadvantages Bad things about this pattern. Possible contraindications. - ## Discussion A deeper discussion about this pattern. You might want to cover how this is done in other languages, alternative approaches, why this is particularly nice in Rust, etc. - ## See also Related patterns (link to the pattern file). Versions of this pattern in other From 60946dd8c716084e58e0eada590b4cf9c37b7fac Mon Sep 17 00:00:00 2001 From: Takashi Idobe Date: Tue, 5 Jan 2021 09:57:07 -0500 Subject: [PATCH 064/217] Add markdownlint to CI (#164) --- .github/workflows/ci.yml | 15 +++++++++++++++ anti_patterns/deref.md | 6 +++--- idioms/coercion-arguments.md | 2 +- idioms/mem-replace.md | 8 ++++---- idioms/rustdoc-init.md | 4 ++-- patterns/RAII.md | 6 +++--- patterns/newtype.md | 4 ++-- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ce1edc3..396a8f2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,3 +41,18 @@ jobs: mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - run: mdbook test + + lint: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Lint all files in current directory + uses: avto-dev/markdown-lint@v1 + with: + config: '.markdownlint.yaml' + args: '*.md' + - name: Lint all files recursively + uses: avto-dev/markdown-lint@v1 + with: + config: '.markdownlint.yaml' + args: '**/*.md' diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index 832d3fa5..e081a805 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -31,8 +31,8 @@ use std::ops::Deref; struct Foo {} impl Foo { - fn m(&self) { - //.. + fn m(&self) { + //.. } } @@ -73,7 +73,7 @@ You save a little boilerplate, e.g., ```rust,ignore impl Bar { - fn m(&self) { + fn m(&self) { self.f.m() } } diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index b9a18a6a..dd59f01f 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -93,7 +93,7 @@ fn three_vowels(word: &str) -> bool { } fn main() { - let sentence_string = + let sentence_string = "Once upon a time, there was a friendly curious crab named Ferris".to_string(); for word in sentence_string.split(' ') { if three_vowels(word) { diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index 5f3bd50d..b1273168 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -22,15 +22,15 @@ fn a_to_b(e: &mut MyEnum) { // we mutably borrow `e` here. This precludes us from changing it directly // as in `*e = ...`, because the borrow checker won't allow it. Therefore - // the assignment to `e` must be outside the `if let` clause. + // the assignment to `e` must be outside the `if let` clause. *e = if let MyEnum::A { ref mut name, x: 0 } = *e { - + // this takes out our `name` and put in an empty String instead // (note that empty strings don't allocate). - // Then, construct the new enum variant (which will + // Then, construct the new enum variant (which will // be assigned to `*e`, because it is the result of the `if let` expression). MyEnum::B { name: mem::replace(name, String::new()) } - + // In all other cases, we return immediately, thus skipping the assignment } else { return } } diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 89b00f4e..d3f3e997 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -33,7 +33,7 @@ impl Connection { fn send_request(&self, request: Request) -> Result { // ... } - + /// Oh no, all that boilerplate needs to be repeated here! fn check_status(&self) -> Status { // ... @@ -58,7 +58,7 @@ impl Connection { /// ``` /// # fn call_send(connection: Connection, request: Request) { /// let response = connection.send_request(); - /// assert!(response.is_ok()); + /// assert!(response.is_ok()); /// # } /// ``` fn send_request(&self, request: Request) { diff --git a/patterns/RAII.md b/patterns/RAII.md index b576a80a..2024d201 100644 --- a/patterns/RAII.md +++ b/patterns/RAII.md @@ -35,9 +35,9 @@ impl Mutex { //.. // MutexGuard keeps a reference to self - MutexGuard { - data: self, - //.. + MutexGuard { + data: self, + //.. } } } diff --git a/patterns/newtype.md b/patterns/newtype.md index 7668222a..5e127644 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -35,9 +35,9 @@ impl Bar { pub fn new( //.. ) -> Bar { - + //.. - + } //.. From 501ae92a43ce6fc2f1b8d6a4299d243feed2f85e Mon Sep 17 00:00:00 2001 From: Weipin Xia Date: Tue, 5 Jan 2021 23:02:16 +0800 Subject: [PATCH 065/217] Fix missing argument in rustdoc-init.md (#166) --- idioms/rustdoc-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index d3f3e997..9badae4a 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -57,7 +57,7 @@ impl Connection { /// # Example /// ``` /// # fn call_send(connection: Connection, request: Request) { - /// let response = connection.send_request(); + /// let response = connection.send_request(request); /// assert!(response.is_ok()); /// # } /// ``` From 11a4b712c05c08e1638acded187cf760832ed4f0 Mon Sep 17 00:00:00 2001 From: jhwgh1968 Date: Tue, 5 Jan 2021 15:44:31 +0000 Subject: [PATCH 066/217] Several FFI Sections: Strings, Errors, and API Design (#106) --- README.md | 1 - SUMMARY.md | 8 ++ idioms/ffi-accepting-strings.md | 113 +++++++++++++++++ idioms/ffi-errors.md | 134 ++++++++++++++++++++ idioms/ffi-intro.md | 12 ++ idioms/ffi-passing-strings.md | 95 ++++++++++++++ patterns/ffi-export.md | 215 ++++++++++++++++++++++++++++++++ patterns/ffi-intro.md | 10 ++ patterns/ffi-wrappers.md | 138 ++++++++++++++++++++ 9 files changed, 725 insertions(+), 1 deletion(-) create mode 100644 idioms/ffi-accepting-strings.md create mode 100644 idioms/ffi-errors.md create mode 100644 idioms/ffi-intro.md create mode 100644 idioms/ffi-passing-strings.md create mode 100644 patterns/ffi-export.md create mode 100644 patterns/ffi-intro.md create mode 100644 patterns/ffi-wrappers.md diff --git a/README.md b/README.md index 9956c877..c35e3670 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). * TODO trait to separate visibility of methods from visibility of data () * TODO leak amplification ("Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration") * TODO interior mutability - UnsafeCell, Cell, RefCell -* TODO FFI usage (By being mindful of how to provide Rust libraries, and make use of existing libraries across the FFI, you can get more out of benefits Rust can bring) ### Design patterns diff --git a/SUMMARY.md b/SUMMARY.md index 8429b73e..ed2eddfe 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -11,6 +11,10 @@ - [Finalisation in Destructors](./idioms/dtor-finally.md) - [`mem::replace(_)`](./idioms/mem-replace.md) - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) + - [Foreign function interface usage](./idioms/ffi-intro.md) + - [Idiomatic Errors](./idioms/ffi-errors.md) + - [Accepting Strings](./idioms/ffi-accepting-strings.md) + - [Passing Strings](./idioms/ffi-passing-strings.md) - [Iterating over an `Option`](./idioms/option-iter.md) - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) - [Privacy For Extensibility](./idioms/priv-extend.md) @@ -20,6 +24,10 @@ - [Design Patterns](./patterns/index.md) - [Builder](./patterns/builder.md) - [Compose Structs](./patterns/compose-structs.md) + - [Entry API](./patterns/entry.md) + - [Foreign function interface usage](./patterns/ffi-intro.md) + - [Object-Based APIs](./patterns/ffi-export.md) + - [Type Consolidation into Wrappers](./patterns/ffi-wrappers.md) - [Fold](./patterns/fold.md) - [Newtype](./patterns/newtype.md) - [RAII Guards](./patterns/RAII.md) diff --git a/idioms/ffi-accepting-strings.md b/idioms/ffi-accepting-strings.md new file mode 100644 index 00000000..0deffff1 --- /dev/null +++ b/idioms/ffi-accepting-strings.md @@ -0,0 +1,113 @@ +# Accepting Strings + +## Description + +When accepting strings via FFI through pointers, there are two principles that should be followed: + +1. Keep foreign strings "borrowed", rather than copying them directly. +2. Minimize `unsafe` code during the conversion. + +## Motivation + +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 are being accepted from a foreign caller of a Rust function. + +The best practice is simple: use `CStr` in such a way as to minimize unsafe code, and create a borrowed slice. +If an owned String is needed, call `to_string()` on the string slice. + +## Code Example + +```rust,ignore +pub mod unsafe_module { + + // other module content + + #[no_mangle] + pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) { + let level: crate::LogLevel = match level { /* ... */ }; + + let msg_str: &str = unsafe { + // SAFETY: accessing raw pointers expected to live for the call, + // and creating a shared reference that does not outlive the current + // stack frame. + match std::ffi::CStr::from_ptr(msg).to_str() { + Ok(s) => s, + Err(e) => { + crate::log_error("FFI string conversion failed"); + return; + } + } + }; + + crate::log(msg_str, level); + } +} +``` + +## Advantages + +The example is is written to ensure that: + +1. The `unsafe` block is as small as possible. +2. The pointer with an "untracked" lifetime becomes a "tracked" shared reference + +Consider an alternative, where the string is actually copied: + +```rust,ignore +pub mod unsafe_module { + + // other module content + + pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) { + /* DO NOT USE THIS CODE. IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG. */ + + let level: crate::LogLevel = match level { /* ... */ }; + + let msg_len = unsafe { /* SAFETY: strlen is what it is, I guess? */ + libc::strlen(msg) + }; + + let mut msg_data = Vec::with_capacity(msg_len + 1); + + let msg_cstr: std::ffi::CString = unsafe { + // SAFETY: copying from a foreign pointer expected to live + // for the entire stack frame into owned memory + std::ptr::copy_nonoverlapping(msg, msg_data.as_mut(), msg_len); + + msg_data.set_len(msg_len + 1); + + std::ffi::CString::from_vec_with_nul(msg_data).unwrap() + } + + let msg_str: String = unsafe { + match msg_cstr.into_string() { + Ok(s) => s, + Err(e) => { + crate::log_error("FFI string conversion failed"); + return; + } + } + }; + + crate::log(&msg_str, level); + } +} +``` + +This code in inferior to the original in two respects: + +1. There is much more `unsafe` code, and more importantly, more invariants it must uphold. +2. Due to the extensive arithmetic required, there is a bug in this version that cases Rust `undefined behaviour`. + +The bug here is a simple mistake in pointer arithmetic: the string was copied, all `msg_len` bytes of it. +However, the `NUL` terminator at the end was not. + +The Vector then had its size *set* to the length of the *zero padded string* -- 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`! + +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 put a weird character at the end of the string, sometimes it would just completely crash. + +## Disadvantages + +None? diff --git a/idioms/ffi-errors.md b/idioms/ffi-errors.md new file mode 100644 index 00000000..3bdeec41 --- /dev/null +++ b/idioms/ffi-errors.md @@ -0,0 +1,134 @@ +# Error Handling in FFI + +## Description + +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 a propogated through a full type. + +This best practice shows different kinds of error codes, and how to expose them in a usable way: + +1. Flat Enums should be converted to integers and returned as codes. +2. Structured Enums should be converted to an integer code with a string error message for detail. +3. Custom Error Types should become "transparent", with a C representation. + +## Code Example + +### Flat Enums + +```rust,ignore +enum DatabaseError { + IsReadOnly = 1, // user attempted a write operation + IOError = 2, // user should read the C errno() for what it was + FileCorrupted = 3, // user should run a repair tool to recover it +} + +impl From for libc::c_int { + fn from(e: DatabaseError) -> libc::c_int { + (e as i8).into() + } +} +``` + +### Structured Enums + +```rust,ignore +pub mod errors { + enum DatabaseError { + IsReadOnly, + IOError(std::io::Error), + FileCorrupted(String), // message describing the issue + } + + impl From for libc::c_int { + fn from(e: DatabaseError) -> libc::c_int { + match e { + DatabaseError::IsReadOnly => 1, + DatabaseError::IOError(_) => 2, + DatabaseError::FileCorrupted(_) => 3, + } + } + } +} + +pub mod c_api { + use super::errors::DatabaseError; + + #[no_mangle] + pub extern "C" fn db_error_description( + e: *const DatabaseError + ) -> *mut libc::c_char { + + let error: &DatabaseError = unsafe { + /* SAFETY: pointer lifetime is greater than the current stack frame */ + &*e + }; + + let error_str: String = match error { + DatabaseError::IsReadOnly => { + format!("cannot write to read-only database"); + } + DatabaseError::IOError(e) => { + format!("I/O Error: {}", e); + } + DatabaseError::FileCorrupted(s) => { + format!("File corrupted, run repair: {}", &s); + } + }; + + let c_error = unsafe { + // SAFETY: copying error_str to an allocated buffer with a NUL + // character at the end + let mut malloc: *mut u8 = libc::malloc(error_str.len() + 1) as *mut _; + + if malloc.is_null() { + return std::ptr::null_mut(); + } + + let src = error_str.as_bytes().as_ptr(); + + std::ptr::copy_nonoverlapping(src, malloc, error_str.len()); + + std::ptr::write(malloc.add(error_str.len()), 0); + + malloc as *mut libc::c_char + }; + + c_error + } +} +``` + +### Custom Error Types + +```rust,ignore +struct ParseError { + expected: char, + line: u32, + ch: u16 +} + +impl ParseError { /* ... */ } + +/* Create a second version which is exposed as a C structure */ +#[repr(C)] +pub struct parse_error { + pub expected: libc::c_char, + pub line: u32, + pub ch: u16 +} + +impl From for parse_error { + fn from(e: ParseError) -> parse_error { + let ParseError { expected, line, ch } = e; + parse_error { expected, line, ch } + } +} +``` + +## Advantages + +This ensures that the foreign language has clear access to error information while not compromising the Rust code's API at all. + +## Disadvantages + +It's a lot of typing, and some types may not be able to be converted easily to C. diff --git a/idioms/ffi-intro.md b/idioms/ffi-intro.md new file mode 100644 index 00000000..9c58b744 --- /dev/null +++ b/idioms/ffi-intro.md @@ -0,0 +1,12 @@ +# FFI Idioms + +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. + +This section contains idioms that may be useful when doing FFI. + +1. [Idiomatic Errors](./ffi-errors.md) - Error handling with integer codes and sentinel return values (such as `NULL` pointers) + +2. [Accepting Strings](./ffi-accepting-strings.md) with minimal unsafe code + +3. [Passing Strings](./ffi-passing-strings.md) to FFI functions diff --git a/idioms/ffi-passing-strings.md b/idioms/ffi-passing-strings.md new file mode 100644 index 00000000..246961c1 --- /dev/null +++ b/idioms/ffi-passing-strings.md @@ -0,0 +1,95 @@ +# Passing Strings + +## Description + +When passing strings to FFI functions, there are four principles that should be followed: + +1. Make the lifetime of owned strings as long as possible. +2. Minimize `unsafe` code during the conversion. +3. If the C code can modify the string data, use `Vec` instead of `CString`. +4. Unless the Foreign Function API requires it, the ownership of the string should not transfer to the callee. + +## Motivation + +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 are being sent to a foreign function call from a Rust function. + +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. + +## Code Example + +```rust,ignore +pub mod unsafe_module { + + // other module content + + extern "C" { + fn seterr(message: *const libc::c_char); + fn geterr(buffer: *mut libc::c_char, size: libc::c_int) -> libc::c_int; + } + + fn report_error_to_ffi>( + err: S + ) -> Result<(), std::ffi::NulError>{ + let c_err = std::ffi::CString::new(err.into())?; + + unsafe { + // SAFETY: calling an FFI whose documentation says the pointer is + // const, so no modificationshould occur + seterr(c_err.as_ptr()); + } + + Ok(()) + // The lifetime of c_err continues until here + } + + fn get_error_from_ffi() -> Result { + let mut buffer = vec![0u8; 1024]; + unsafe { + // SAFETY: calling an FFI whose documentation implies + // that the input need only live as long as the call + let written: usize = geterr(buffer.as_mut_ptr(), 1023).into(); + + buffer.truncate(written + 1); + } + + std::ffi::CString::new(buffer).unwrap().into_string() + } +} +``` + +## Advantages + +The example is written in a way to ensure that: + +1. The `unsafe` block is as small as possible. +2. The `CString` lives long enough. +3. Errors with typecasts are always propagated when possible. + +A common mistake (so common it's in the documentation) is to not use the variable in the first block: + +```rust,ignore +pub mod unsafe_module { + + // other module content + + fn report_error>(err: S) -> Result<(), std::ffi::NulError> { + unsafe { + // SAFETY: whoops, this contains a dangling pointer! + seterr(std::ffi::CString::new(err.into())?.as_ptr()); + } + Ok(()) + } +} +``` + +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 created. + +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 system's ability to return zeroed memory (which is quite fast). + +## Disadvantages + +None? diff --git a/patterns/ffi-export.md b/patterns/ffi-export.md new file mode 100644 index 00000000..4a83b165 --- /dev/null +++ b/patterns/ffi-export.md @@ -0,0 +1,215 @@ +# Object-Based APIs + +## Description + +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: + +1. All Encapsulated types should be *owned* by Rust, *managed* by the user, and *opaque*. +2. All Transactional data types should be *owned* by the user, and *transparent*. +3. All library behavior should be functions acting upon Encapsulated types. +4. All library behavior should be encapsulated into types not based on structure, but *provenance/lifetime*. + +## Motivation + +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). + +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: + +1. Make it easy to use in the target language. +2. Avoid the API dictating internal unsafety on the Rust side as much as possible. +3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small as possible. + +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`. + +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. + +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`. + +## Code Example + +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. + +Here is the definition in C, which hopefully should be easy to read for those involved in FFI. +The commentary below should help explaining it for those who miss the subtleties. + +```C +struct DBM; +typedef struct { void *dptr, size_t dsize } datum; + +int dbm_clearerr(DBM *); +void dbm_close(DBM *); +int dbm_delete(DBM *, datum); +int dbm_error(DBM *); +datum dbm_fetch(DBM *, datum); +datum dbm_firstkey(DBM *); +datum dbm_nextkey(DBM *); +DBM *dbm_open(const char *, int, mode_t); +int dbm_store(DBM *, datum, datum, int); +``` + +This API defines two types: `DBM` and `datum`. + +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. + +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*. + +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. + +The `datum` type was called a "transactional" type above. It is designed to facilitate the exchange of information between the library and its user. + +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. + +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`. + +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? + +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. + +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 is what this best practice is about, and the key is to *transfer ownership of everything that is transparent*. + +## Advantages + +This minimizes the number of memory safety guarantees the user must uphold to a relatively small number: + +1. Do not call any function with a pointer not returned by `dbm_open` (invalid access or corruption). +2. Do not call any function on a pointer after close (use after free). +3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of memory at the advertised length. + +In addition, it avoids a lot of pointer provenance issues. +To understand why, let us consider an alternative in some depth: key iteration. + +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. + +Here is how iteration would be done in Rust for `DBM`: + +```rust,ignore +struct Dbm { ... } + +impl Dbm { + /* ... */ + pub fn keys<'it>(&'it self) -> DbmKeysIter<'it> { ... } + /* ... */ +} + +struct DbmKeysIter<'it> { + owner: &'it Dbm, +} + +impl<'it> Iterator for DbmKeysIter<'it> { ... } +``` + +This is clean, idiomatic, and safe. thanks to Rust's guarantees. +However, consider what a straightforward API translation would look like: + +```rust,ignore +#[no_mangle] +pub extern "C" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter { + /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ +} +#[no_mangle] +pub extern "C" fn dbm_iter_next(iter: *mut DbmKeysIter, key_out: *const datum) -> libc::c_int { + /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ +} +#[no_mangle] +pub extern "C" fn dbm_iter_del(*mut DbmKeysIter) { + /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ +} +``` + +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. + +This example written in C contains a bug that will be explained afterwards: + +```C +int count_key_sizes(DBM *db) { + /* DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG! */ + datum key; + int len = 0; + + if (!dbm_iter_new(db)) { + dbm_close(db); + return -1; + } + + int l; + while ((l = dbm_iter_next(owner, &key)) >= 0) { // an error is indicated by -1 + free(key.dptr); + len += key.dsize; + if (l == 0) { // end of the iterator + dbm_close(owner); + } + } + if l >= 0 { + return -1; + } else { + return len; + } +} +``` + +This bug is a classic. Here's what happens when the iterator returns the end-of-iteration marker: + +1. The loop condition sets `l` to zero, and enters the loop because `0 >= 0`. +2. The length is incremented, in this case by zero. +3. The if statement is true, so the database is closed. There should be a break statement here. +4. The loop condition executes again, causing a `next` call on the closed object. + +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! + +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". + +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: + +```C +datum dbm_firstkey(DBM *); +datum dbm_nextkey(DBM *); +``` + +Thus, all of the lifetimes were bound together, and such unsafety was prevented. + +## Disadvantages + +However, this design choice also has a number of drawbacks, which should be considered as well. + +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. + +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: + +- [Wrapper Type Consolidation](./ffi-wrappers.md) groups multiple Rust types together into an opaque "object" + +- [FFI Error Passing](../idioms/ffi-errors.md) explains error handling with integer codes and sentinel return values (such as `NULL` pointers) + +- [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) + +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. diff --git a/patterns/ffi-intro.md b/patterns/ffi-intro.md new file mode 100644 index 00000000..d6d6b192 --- /dev/null +++ b/patterns/ffi-intro.md @@ -0,0 +1,10 @@ +# FFI Patterns + +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. + +This section contains design patterns that may be useful when doing FFI. + +1. [Object-Based API](./ffi-export.md) design that has good memory safety characteristics, and a clean boundary of what is safe and what is unsafe + +2. [Type Consolidation into Wrappers](./ffi-wrappers.md) - group multiple Rust types together into an opaque "object" diff --git a/patterns/ffi-wrappers.md b/patterns/ffi-wrappers.md new file mode 100644 index 00000000..f761fe12 --- /dev/null +++ b/patterns/ffi-wrappers.md @@ -0,0 +1,138 @@ +# Type Consolidation into Wrappers + +## Description + +This pattern is designed to allow gracefully handling multiple related types, while minimizing the surface area for memory unsafety. + +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. + +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. + +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. + +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. + +## Code Example + +To understand this, let us look at a classic example of an API to export: iteration through a collection. + +That API looks like this: + +1. The iterator is initialized with `first_key`. +2. Each call to `next_key` will advance the iterator. +3. Calls to `next_key` if the iterator is at the end will do nothing. +4. As noted above, the iterator is "wrapped into" the collection (unlike the native Rust API). + +If the iterator implements `nth()` efficiently, then it is possible to make it ephemeral to each function call: + +```rust,ignore +struct MySetWrapper { + myset: MySet, + iter_next: usize, +} + +impl MySetWrapper { + pub fn first_key(&mut self) -> Option<&Key> { + self.iter_next = 0; + self.next_key() + } + pub fn next_key(&mut self) -> Option<&Key> { + if let Some(next) = self.myset.keys().nth(self.iter_next) { + self.iter_next += 1; + Some(next) + } else { + None + } + } +} +``` + +As a result, the wrapper is simple and contains no `unsafe` code. + +## Advantages + +This makes APIs safer to use, avoiding issues with lifetimes between types. +See [Object-Based APIs](./ffi-export.md) for more on the advantages and pitfalls this avoids. + +## Disadvantages + +Often, wrapping types is quite difficult, and sometimes a Rust API compromise would make things easier. + +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. + +### Trying to Wrap Iterators (and Failing) + +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. + +Suffice it to say, this is *incredibly* difficult. + +Here is an illustration of just *one* pitfall. + +A first version of `MySetWrapper` would look like this: + +```rust,ignore +struct MySetWrapper { + myset: MySet, + iter_next: usize, + // created from a transmuted Box + iterator: Option>>, +} +``` + +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`*. + +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. + +A simple implementation of `myset_store` would be: + +```rust,ignore +pub mod unsafe_module { + + // other module content + + pub fn myset_store( + myset: *mut MySetWrapper, + key: datum, + value: datum) -> libc::c_int { + + /* DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM. */ + + let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in here! + &mut (*myset).myset + }; + + /* ...check and cast key and value data... */ + + match myset.store(casted_key, casted_value) { + Ok(_) => 0, + Err(e) => e.into() + } + } +} +``` + +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] + +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. + +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 has an entire lexicon dedicated to concurrent behavior!](https://manpages.debian.org/buster/manpages/attributes.7.en.html) + +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. + +[^1]: For the C programmers out there scratching their heads, the iterator need not be read *during* this code 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. From 6a5854378250e1dc84e4bc72c6855aa14a9336fb Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:13:41 +0100 Subject: [PATCH 067/217] Add participation to Introduction (#160) --- SUMMARY.md | 2 +- intro.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index ed2eddfe..6b78d2be 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,7 +1,7 @@ # Summary - [Introduction](./intro.md) - +- [Contributing](./CONTRIBUTING.md) - [Idioms](./idioms/index.md) - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) diff --git a/intro.md b/intro.md index 9a423b44..55cc7be3 100644 --- a/intro.md +++ b/intro.md @@ -1,5 +1,9 @@ # Introduction +## Participation + +If you are interested in contributing to the Patterns catalogue, check out the [contribution guidelines](./CONTRIBUTING.md). + ## Design patterns When developing programs, we have to solve many problems. A program can be viewed as a solution to a problem. It can also be viewed as a collection of solutions to many different problems. All of these solutions work together to solve a bigger problem. From 1f688d7ae27cc9b3b6b17560e9010e2438a706bc Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:18:52 +0100 Subject: [PATCH 068/217] Writing an introduction for the contribution guide (#161) Co-authored-by: Takashi Idobe --- CONTRIBUTING.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9d0ed54..7bbe07ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,15 @@ # Contributing +## Introduction + +This book is a catalogue of Rust programming techniques, (anti-)patterns, idioms and other explanations. +It is a compilation of collective (sometimes implicit) knowledge as well as experiences that have emerged through collaborative work. + +The patterns described here are __not rules__, but should be taken as guidelines for writing idiomatic code in Rust. +We are collecting Rust patterns in this book so people can learn the tradeoffs between Rust idioms and use them properly in their own code. + +If you want to be part of this effort here are some ways you can participate: + ## Discussion board If you have a question or an idea regarding certain content but you want to have feedback of fellow community members From a9848987ceb9123762cfe7fe260dd6f49eaefcba Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:23:53 +0100 Subject: [PATCH 069/217] Adding informative links to Builder pattern (#158) --- patterns/builder.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/patterns/builder.md b/patterns/builder.md index c3612a22..c08c4a91 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -98,10 +98,8 @@ as well as the `FooBuilder::new().a().b().build()` style. ## See also -[Description in the style guide](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html) - -[derive_builder](https://crates.io/crates/derive_builder), a crate for automatically implementing this pattern while avoiding the boilerplate. - -[Constructor pattern](../idioms/ctor.md) for when construction is simpler. - -[Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) +- [Description in the style guide](https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html) +- [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically implementing this pattern while avoiding the boilerplate. +- [Constructor pattern](../idioms/ctor.md) for when construction is simpler. +- [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) +- [Builders enable construction of complex values (C-BUILDER)](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) from the Rust API guidelines From dfd74a86d14e480c7f1b909a496714f1280a5ade Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:30:53 +0100 Subject: [PATCH 070/217] Adding some additional resources (#159) --- additional_resources.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/additional_resources.md b/additional_resources.md index da6feac9..0ee43775 100644 --- a/additional_resources.md +++ b/additional_resources.md @@ -4,4 +4,10 @@ A collection of complementary helpful content ## Talks -- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by Nick Cameron at the PDRust (2016) +- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by Nicholas Cameron at the PDRust (2016) +- [Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?v=0zOg8_B71gE) by Pascal Hertleif at RustFest (2017) +- [Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) by Nicholas Cameron at LinuxConfAu (2018) + +## Books (Online) + +- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines) From 66f79d5dddc2c4d043e25d6247e8c0afb2508669 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 6 Jan 2021 11:05:50 +0100 Subject: [PATCH 071/217] Fix typo (#169) * Fix typo * Update CONTRIBUTING.md Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7bbe07ba..44932516 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,6 +56,6 @@ code examples are correct. ### Important Note -Please **don't force push** your branch to keep commit history and make it easier of us to see changes between reviews. +Please **don't force push** commits in your branch, in order to keep commit history and make it easier for us to see changes between reviews. Make sure to `Allow edits of maintainers` (under the text box) in the PR so people can actually collaborate on things or fix smaller issues themselves. From e93c52049c016552c8ec215bb9e0fb734f3317ac Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 12:03:49 +0100 Subject: [PATCH 072/217] CI: Simplify lint job (#174) --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 396a8f2f..bfaf7fcd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,11 +46,6 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Lint all files in current directory - uses: avto-dev/markdown-lint@v1 - with: - config: '.markdownlint.yaml' - args: '*.md' - name: Lint all files recursively uses: avto-dev/markdown-lint@v1 with: From 8ce84d4d6429ef8bc3d2bc97c791d2e1a604cc28 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 13:15:28 +0100 Subject: [PATCH 073/217] Add description for offline usage of markdown lints (#173) --- CONTRIBUTING.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 44932516..6411c5db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,30 @@ Don't forget to add your new article to the `SUMMARY.md` to let it be rendered t Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). +## Check the article locally + +Before submitting the PR launch the commands `mdbook build` to make sure that the book builds and `mdbook test` to make sure that +code examples are correct. + +### Markdown lint + +To make sure the files comply with our Markdown style we use [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). +To spare you some manual work to get through the CI test you can use the following commands to automatically fix most of the emerging problems when writing Markdown files. + +- Install: + + ```sh + npm install -g markdownlint-cli + ``` + +- Check all markdown files: + - unix: `markdownlint '**/*.md'` + - windows: `markdownlint **/*.md` + +- Automatically fix basic errors: + - unix: `markdownlint -f '**/*.md'` + - windows: `markdownlint -f **/*.md` + ## Creating a Pull Request "Release early and often!" also applies to pull requests! @@ -49,11 +73,6 @@ Early reviews of the community are not meant as an offense but to give feedback. A good principle: "Work together, share ideas, teach others." -### Test the book locally before submitting - -Before submitting the PR launch the commands `mdbook build` to make sure that the book builds and `mdbook test` to make sure that -code examples are correct. - ### Important Note Please **don't force push** commits in your branch, in order to keep commit history and make it easier for us to see changes between reviews. From d6f98eaa6eea762ba72655817de14f0aaa8201f9 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 6 Jan 2021 13:55:05 +0100 Subject: [PATCH 074/217] Updating Contrib (#181) * Updating Contrib * add to contributing * Update CONTRIBUTING.md Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- CONTRIBUTING.md | 8 +++++--- README.md | 38 +++----------------------------------- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6411c5db..354d01ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,9 +17,11 @@ and you think it may not be appropriate to file an issue open a discussion in ou ## Writing a new article -Before writing a new article please check our [issues](https://github.com/rust-unofficial/patterns/issues) and -the [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) if there are existing issues or someone -is working on that topic. +Before writing a new article please check in one of the following resources if there is an existing discussion or if someone is already working on that topic: + +- [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116), +- [All issues](https://github.com/rust-unofficial/patterns/issues), +- [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) If you don't find an issue regarding your topic and you are sure it is not more feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) please open a new issue, so we can discuss about the ideas and future content of the article together and maybe diff --git a/README.md b/README.md index c35e3670..2d6fd1db 100644 --- a/README.md +++ b/README.md @@ -3,46 +3,14 @@ An open source book about design patterns and idioms in the Rust programming language that you can read [here](https://rust-unofficial.github.io/patterns/). -## TODOs - -### Idioms - -* TODO stability for extensibility -* TODO trait to separate visibility of methods from visibility of data () -* TODO leak amplification ("Vec::drain sets the Vec's len to 0 prematurely so that mem::forgetting Drain "only" mem::forgets more stuff. instead of exposing uninitialized memory or having to update the len on every iteration") -* TODO interior mutability - UnsafeCell, Cell, RefCell - -### Design patterns - -* TODO iterators (to safely avoid bounds checks) -* TODO closures and lifetimes (coupling to lifetime) -* TODO platform-specific sub-modules () -* TODO Module organisation (by looking at examples such as Rusts `libstd`, and how it integrated into the Rusts source code, lessons can be learned about ergonomic project management and API design. Closely assosciated with platform-specific sub-modules) -* [Entry API](patterns/entry.md) (Currently just a boilerplate) -* TODO extension traits -* TODO destructor bombs (ensure linear typing dynamically, e.g., ) -* TODO convertible to Foo trait for more generic generics (e.g., ) -* [Late bound bounds](patterns/late-bounds.md) (Currently just a boilerplate) -* TODO 'shadow' borrowed version of struct - e.g., double buffering, Niko's parser generator -* TODO composition of structs to please the borrow checker -* TODO `Error` traits and `Result` forwarding -* TODO graphs - -### Anti-patterns - -* TODO thread + catch_panic for exceptions -* TODO Clone to satisfy the borrow checker -* TODO Matching all fields of a struct (back compat) -* TODO wildcard matches -* TODO taking an enum rather than having multiple functions -* TODO `unwrap()`ing every `Result` instead of forwarding it - ## Contributing You are missing content in this repository that can be helpful for others and you are eager to explain it? Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. -We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how it works. +You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) for all the patterns, anti-patterns, and idioms that could be added. + +We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how contributing to this repository works. ## Building with mdbook From 5fedf5aa292affe68b320b6bb7b6810334550fbb Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 14:55:55 +0100 Subject: [PATCH 075/217] Markdownlint: Do not allow tabs in code blocks (#178) --- .markdownlint.yaml | 2 -- functional/index.md | 2 +- idioms/pass-var-to-closure.md | 2 +- idioms/temporary-mutability.md | 6 +++--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index b44e3861..41ea1865 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -1,5 +1,3 @@ --- MD004: false -MD010: - code_blocks: false MD013: false diff --git a/functional/index.md b/functional/index.md index 54126bc0..c32031d6 100644 --- a/functional/index.md +++ b/functional/index.md @@ -7,7 +7,7 @@ Rust is an imperative language, but it follows many functional programming parad ```rust let mut sum = 0; for i in 1..11 { - sum += i; + sum += i; } println!("{}", sum); ``` diff --git a/idioms/pass-var-to-closure.md b/idioms/pass-var-to-closure.md index b9b3c329..17c0031b 100644 --- a/idioms/pass-var-to-closure.md +++ b/idioms/pass-var-to-closure.md @@ -40,7 +40,7 @@ let num3 = Rc::new(3); let num2_cloned = num2.clone(); let num3_borrowed = num3.as_ref(); let closure = move || { - *num1 + *num2_cloned + *num3_borrowed; + *num1 + *num2_cloned + *num3_borrowed; }; ``` diff --git a/idioms/temporary-mutability.md b/idioms/temporary-mutability.md index d473a12d..94f7eea4 100644 --- a/idioms/temporary-mutability.md +++ b/idioms/temporary-mutability.md @@ -15,9 +15,9 @@ Using nested block: ```rust,ignore let data = { - let mut data = get_vec(); - data.sort(); - data + let mut data = get_vec(); + data.sort(); + data }; // Here `data` is immutable. From 76ae5bd89658682eb86d672cf808b4d20b1e1ead Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 14:58:26 +0100 Subject: [PATCH 076/217] Reduce long lines (#176) --- .markdownlint.yaml | 5 ++++- functional/index.md | 20 ++++++++++++++++---- idioms/priv-extend.md | 12 +++++++++--- patterns/small-crates.md | 11 ++++++++--- patterns/unsafe-mods.md | 9 +++++++-- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 41ea1865..9f357225 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -1,3 +1,6 @@ --- MD004: false -MD013: false +MD010: + code_blocks: false +MD013: + line_length: 300 diff --git a/functional/index.md b/functional/index.md index c32031d6..3836ba71 100644 --- a/functional/index.md +++ b/functional/index.md @@ -1,6 +1,9 @@ # Functional Usage of Rust -Rust is an imperative language, but it follows many functional programming paradigms. 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. +Rust is an imperative language, but it follows many functional programming paradigms. +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. ## Imperative @@ -12,7 +15,11 @@ for i in 1..11 { println!("{}", sum); ``` -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. +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. | `i` | `sum` | |:---:|:-----:| @@ -35,9 +42,14 @@ This is how most of us start out programming. We learn that a program is a set o println!("{}", (1..11).fold(0, |a, b| a + b)); ``` -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. +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. -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`. +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`. | `a` | `b` | result | |:---:|:---:|:------:| diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index a6c77fbb..19550392 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -27,8 +27,14 @@ fn main(s: a::S) { ## Discussion -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 of the fields and use `..` in the pattern, in which case 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. +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 of the fields and use `..` in the pattern, in which case 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. -The downside of this approach is that you might need to add an otherwise 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. +The downside of this approach is that you might need to add an otherwise 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. -If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible. The problem there is exhaustive match expressions. A private variant would force clients to have a `_` wildcard pattern. +If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible. +The problem there is exhaustive match expressions. +A private variant would force clients to have a `_` wildcard pattern. diff --git a/patterns/small-crates.md b/patterns/small-crates.md index f9785958..5cfb3780 100644 --- a/patterns/small-crates.md +++ b/patterns/small-crates.md @@ -4,17 +4,22 @@ Prefer small crates that do one thing well. -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. +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. ## Advantages * Small crates are easier to understand, and encourage more modular code. -* 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. +* 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. * 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. ## Disadvantages -* 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`. +* 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`. * Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious. * Two small crates may be less optimized than one large one, since the compiler does not perform link-time optimization (LTO) by default. diff --git a/patterns/unsafe-mods.md b/patterns/unsafe-mods.md index 6cc0db2f..d5b4c5e8 100644 --- a/patterns/unsafe-mods.md +++ b/patterns/unsafe-mods.md @@ -2,7 +2,10 @@ ## Description -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. +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. ## Advantages @@ -17,7 +20,9 @@ If you have `unsafe` code, create the smallest possible module that can uphold t ## Examples * The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations in submodules, presenting a safe interface to users. -* `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. +* `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. ## See also From 7af948ea49934690dd3637ef8e7b5103f66f4da8 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 6 Jan 2021 15:03:09 +0100 Subject: [PATCH 077/217] Adding design principles overview to additional resources (#179) --- SUMMARY.md | 2 ++ design-principles.md | 68 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 design-principles.md diff --git a/SUMMARY.md b/SUMMARY.md index 6b78d2be..99f93e6a 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -42,3 +42,5 @@ - [Functional Programming](./functional/index.md) - [Additional Resources](./additional_resources.md) + + - [Design principles](./design-principles.md) diff --git a/design-principles.md b/design-principles.md new file mode 100644 index 00000000..e6689bb1 --- /dev/null +++ b/design-principles.md @@ -0,0 +1,68 @@ +# Design principles + +## A brief overview over common design principles + +--- + +## [SOLID](https://en.wikipedia.org/wiki/SOLID) + +- [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. +- [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." +- [Liscov 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." +- [Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/Interface_segregation_principle): + "Many client-specific interfaces are better than one general-purpose interface." +- [Dependency Inversion Principle (DIP)](https://en.wikipedia.org/wiki/Dependency_inversion_principle): + One should "depend upon abstractions, [not] concretions." + +## [DRY (Don’t Repeat Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) + +"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system" + +## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) + +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 + +## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter) + +a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents), in accordance with the principle of "information hiding" + +## [Design by contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract) + +software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants + +## [Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) + +bundling of data with the methods that operate on that data, or the 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. + +## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) + +“Functions should not produce abstract side effects...only commands (procedures) will be permitted to produce side effects.” - Bertrand Meyer: Object Oriented Software Construction + +## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) + +a component of a system should behave in a way that most users will expect it to behave. The behavior should not astonish or surprise users + +## Linguistic-Modular-Units + +“Modules must correspond to syntactic units in the language used.” - Bertrand Meyer: Object Oriented Software Construction + +## Self-Documentation + +“The designer of a module should strive to make all information about the module part of the module itself.” - Bertrand Meyer: Object Oriented Software Construction + +## Uniform-Access + +“All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.” - Bertrand Meyer: Object Oriented Software Construction + +## Single-Choice + +“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: Object Oriented Software Construction + +## Persistence-Closure + +“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 From 48a530218cf5be2cf9530a752a514041a754a4e3 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 15:04:40 +0100 Subject: [PATCH 078/217] markdownlint: fix md004 (#175) * markdownlint: fix md004 * use `-` for lists Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- .markdownlint.yaml | 1 - patterns/newtype.md | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 9f357225..87a22d65 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -1,5 +1,4 @@ --- -MD004: false MD010: code_blocks: false MD013: diff --git a/patterns/newtype.md b/patterns/newtype.md index 5e127644..8eadde3a 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -86,9 +86,9 @@ the wrapper type. Newtypes are very common in Rust code. Abstraction or representing units are the most common uses, but they can be used for other reasons: -* restricting functionality (reduce the functions exposed or traits implemented), -* making a type with copy semantics have move semantics, -* abstraction by providing a more concrete type and thus hiding internal types, e.g., +- restricting functionality (reduce the functions exposed or traits implemented), +- making a type with copy semantics have move semantics, +- abstraction by providing a more concrete type and thus hiding internal types, e.g., ```rust,ignore pub struct Foo(Bar); From 3ee9110615db27bbc17b2671f950ea2b8c21a301 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 15:08:04 +0100 Subject: [PATCH 079/217] CI: Rename markdownlint job (#180) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfaf7fcd..753412bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: - run: mdbook test - lint: + markdown-lint: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 From a0e765179ddf985af4b1f22d71df17254a597a9c Mon Sep 17 00:00:00 2001 From: Andreas Schmidt Date: Wed, 6 Jan 2021 15:18:34 +0100 Subject: [PATCH 080/217] Add note on #[non_exhaustive] for enums (#168) Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- idioms/priv-extend.md | 1 + 1 file changed, 1 insertion(+) diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index 19550392..56274769 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -38,3 +38,4 @@ You can use the `()` type so that there is no runtime overhead and prepend `_` t If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible. The problem there is exhaustive match expressions. A private variant would force clients to have a `_` wildcard pattern. +A common way to implement this instead is using the [#[non_exhaustive]](https://doc.rust-lang.org/reference/attributes/type_system.html) attribute. From ad52fcb8eaff04df988997614ac035d51ab0c602 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 6 Jan 2021 17:46:54 +0100 Subject: [PATCH 081/217] Add and explain markdown linting rules (#183) --- .markdownlint.yaml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 87a22d65..2fe1b31e 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -1,5 +1,21 @@ --- -MD010: - code_blocks: false +# Use `#` for headers +MD003: + style: atx + +# Set maximum line length MD013: line_length: 300 + +# Use `---` for horizontal rule +MD035: + style: --- + +# Use ``` for code blocks +MD046: + style: fenced +MD048: + style: backtick + +# See https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md for +# additional info From ff8bc764de0590645cfde87ae3a15036ed63eab8 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 7 Jan 2021 08:52:35 +0100 Subject: [PATCH 082/217] Create additional_resources directory (#186) --- SUMMARY.md | 5 ++--- .../design-principles.md | 0 additional_resources.md => additional_resources/index.md | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename design-principles.md => additional_resources/design-principles.md (100%) rename additional_resources.md => additional_resources/index.md (100%) diff --git a/SUMMARY.md b/SUMMARY.md index 99f93e6a..a87cb87c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -41,6 +41,5 @@ - [Functional Programming](./functional/index.md) -- [Additional Resources](./additional_resources.md) - - - [Design principles](./design-principles.md) +- [Additional Resources](./additional_resources/index.md) + - [Design principles](./additional_resources/design-principles.md) diff --git a/design-principles.md b/additional_resources/design-principles.md similarity index 100% rename from design-principles.md rename to additional_resources/design-principles.md diff --git a/additional_resources.md b/additional_resources/index.md similarity index 100% rename from additional_resources.md rename to additional_resources/index.md From 6cbbcb82465fb6210bce4d9b545ebfca2323f771 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 7 Jan 2021 09:04:33 +0100 Subject: [PATCH 083/217] Remove contributing from html rendered book (#187) --- SUMMARY.md | 1 - intro.md | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index a87cb87c..7a97dde8 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,7 +1,6 @@ # Summary - [Introduction](./intro.md) -- [Contributing](./CONTRIBUTING.md) - [Idioms](./idioms/index.md) - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) diff --git a/intro.md b/intro.md index 55cc7be3..5950f445 100644 --- a/intro.md +++ b/intro.md @@ -2,7 +2,8 @@ ## Participation -If you are interested in contributing to the Patterns catalogue, check out the [contribution guidelines](./CONTRIBUTING.md). +If you are interested in contributing to the Patterns catalogue, check out the +[contribution guidelines](https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md). ## Design patterns From 868cd2f3f4ab8967027abb0323498e2dffc7a42b Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 7 Jan 2021 09:21:41 +0100 Subject: [PATCH 084/217] intro.md: split lines (#188) --- intro.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/intro.md b/intro.md index 5950f445..93dd06fb 100644 --- a/intro.md +++ b/intro.md @@ -7,11 +7,16 @@ If you are interested in contributing to the Patterns catalogue, check out the ## Design patterns -When developing programs, we have to solve many problems. A program can be viewed as a solution to a problem. It can also be viewed as a collection of solutions to many different problems. All of these solutions work together to solve a bigger problem. +When developing programs, we have to solve many problems. +A program can be viewed as a solution to a problem. +It can also be viewed as a collection of solutions to many different problems. +All of these solutions work together to solve a bigger problem. ## Design patterns in Rust -There are many problems that share the same form. Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods. +There are many problems that share the same form. +Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. +While the details are different, since they have the same form they can be solved using the same fundamental methods. [Design patterns](./patterns/index.md) are methods to solve common problems when writing software. @@ -19,7 +24,8 @@ There are many problems that share the same form. Due to the fact that Rust is n However, while design patterns give us benefits, anti-patterns create more problems. -[Idioms](./idioms/index.md) are guidelines to follow when coding. They are social norms of the community. +[Idioms](./idioms/index.md) are guidelines to follow when coding. +They are social norms of the community. You can break them, but if you do you should have a good reason for it. TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker From f61f2f40f0f98a4cbb50693db1ed86ca89e5c2d8 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 8 Jan 2021 08:59:46 +0100 Subject: [PATCH 085/217] Fix lines to 150 line length for better tracking of future changes (#189) --- .markdownlint.yaml | 2 +- CONTRIBUTING.md | 6 ++-- README.md | 3 +- additional_resources/design-principles.md | 40 ++++++++++++++++------- anti_patterns/index.md | 3 +- functional/index.md | 3 +- idioms/coercion-arguments.md | 20 ++++++++---- idioms/ffi-accepting-strings.md | 7 ++-- idioms/ffi-passing-strings.md | 6 ++-- idioms/index.md | 12 +++++-- idioms/option-iter.md | 16 ++++++--- idioms/priv-extend.md | 3 +- idioms/rustdoc-init.md | 9 +++-- patterns/builder.md | 2 +- patterns/ffi-export.md | 24 +++++++++----- patterns/ffi-wrappers.md | 17 ++++++---- patterns/index.md | 22 +++++++++---- patterns/newtype.md | 4 ++- patterns/small-crates.md | 3 +- refactoring/index.md | 7 ++-- 20 files changed, 144 insertions(+), 65 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 2fe1b31e..864c1db1 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -5,7 +5,7 @@ MD003: # Set maximum line length MD013: - line_length: 300 + line_length: 150 # Use `---` for horizontal rule MD035: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 354d01ce..9fe25bbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,8 @@ and you think it may not be appropriate to file an issue open a discussion in ou ## Writing a new article -Before writing a new article please check in one of the following resources if there is an existing discussion or if someone is already working on that topic: +Before writing a new article please check in one of the following resources if there is +an existing discussion or if someone is already working on that topic: - [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116), - [All issues](https://github.com/rust-unofficial/patterns/issues), @@ -50,7 +51,8 @@ code examples are correct. ### Markdown lint To make sure the files comply with our Markdown style we use [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). -To spare you some manual work to get through the CI test you can use the following commands to automatically fix most of the emerging problems when writing Markdown files. +To spare you some manual work to get through the CI test you can use the following commands to automatically fix +most of the emerging problems when writing Markdown files. - Install: diff --git a/README.md b/README.md index 2d6fd1db..422d2f8c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). You are missing content in this repository that can be helpful for others and you are eager to explain it? Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. -You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) for all the patterns, anti-patterns, and idioms that could be added. +You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) for all the +patterns, anti-patterns, and idioms that could be added. We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how contributing to this repository works. diff --git a/additional_resources/design-principles.md b/additional_resources/design-principles.md index e6689bb1..c002fdfc 100644 --- a/additional_resources/design-principles.md +++ b/additional_resources/design-principles.md @@ -25,44 +25,62 @@ ## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) -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 +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 ## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter) -a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents), in accordance with the principle of "information hiding" +a given object should assume as little as possible about the structure or properties of +anything else (including its subcomponents), in accordance with the principle of "information hiding" ## [Design by contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract) -software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants +software designers should define formal, precise and verifiable interface specifications +for software components, which extend the ordinary definition of abstract data types with +preconditions, postconditions and invariants ## [Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) -bundling of data with the methods that operate on that data, or the 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. +bundling of data with the methods that operate on that data, or the 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. ## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) -“Functions should not produce abstract side effects...only commands (procedures) will be permitted to produce side effects.” - Bertrand Meyer: Object Oriented Software Construction +“Functions should not produce abstract side effects...only commands (procedures) will +be permitted to produce side effects.” - Bertrand Meyer: Object Oriented Software Construction ## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) -a component of a system should behave in a way that most users will expect it to behave. The behavior should not astonish or surprise users +a component of a system should behave in a way that most users will expect it to behave. +The behavior should not astonish or surprise users ## Linguistic-Modular-Units -“Modules must correspond to syntactic units in the language used.” - Bertrand Meyer: Object Oriented Software Construction +“Modules must correspond to syntactic units in the language used.” - Bertrand Meyer: +Object Oriented Software Construction ## Self-Documentation -“The designer of a module should strive to make all information about the module part of the module itself.” - Bertrand Meyer: Object Oriented Software Construction +“The designer of a module should strive to make all information about the module part of +the module itself.” - Bertrand Meyer: Object Oriented Software Construction ## Uniform-Access -“All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.” - Bertrand Meyer: Object Oriented Software Construction +“All services offered by a module should be available through a uniform notation, +which does not betray whether they are implemented through storage or through computation.” - +Bertrand Meyer: Object Oriented Software Construction ## Single-Choice -“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: Object Oriented Software Construction +“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: Object Oriented +Software Construction ## Persistence-Closure -“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 +“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 diff --git a/anti_patterns/index.md b/anti_patterns/index.md index fbae8f2c..5df2acb0 100644 --- a/anti_patterns/index.md +++ b/anti_patterns/index.md @@ -1,6 +1,7 @@ # Anti-patterns -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". +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. diff --git a/functional/index.md b/functional/index.md index 3836ba71..eeab41bd 100644 --- a/functional/index.md +++ b/functional/index.md @@ -42,7 +42,8 @@ This is how most of us start out programming. We learn that a program is a set o println!("{}", (1..11).fold(0, |a, b| a + b)); ``` -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. +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. Here, we are composing functions of addition (this closure: `|a, b| a + b)`) with a range from 1 to 10. diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index dd59f01f..f7bb680f 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -5,14 +5,18 @@ 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. -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__. E.g., `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`. +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`. -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 `String` has a layer of indirection, so a `&String` will have two layers of indrection. +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 `String` has a layer of indirection, so a `&String` will have two layers of indrection. We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. ## Example -For this example, we will illustrate some differences for using `&String` as a function argument versus using a `&str`, but the ideas apply as well to using `&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. +For this example, we will illustrate some differences for using `&String` as a function argument versus using a `&str`, +but the ideas apply as well to using `&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. 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. @@ -70,7 +74,8 @@ 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 anways (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`. -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 has a word that contains three consecutive vowels. +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 has a word that contains three consecutive vowels. We probably should make use of the function we have already defined and simply feed in each word from the sentence. An example of this could look like this: @@ -110,9 +115,12 @@ curious has three consecutive vowels! ``` 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 `&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. +This is because string slices are a `&str` and not 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. ## See also - [Rust Language Reference on Type Coercions](https://doc.rust-lang.org/reference/type-coercions.html) -- 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. +- 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 diff --git a/idioms/ffi-accepting-strings.md b/idioms/ffi-accepting-strings.md index 0deffff1..6dd5af9d 100644 --- a/idioms/ffi-accepting-strings.md +++ b/idioms/ffi-accepting-strings.md @@ -102,11 +102,14 @@ This code in inferior to the original in two respects: The bug here is a simple mistake in pointer arithmetic: the string was copied, all `msg_len` bytes of it. However, the `NUL` terminator at the end was not. -The Vector then had its size *set* to the length of the *zero padded string* -- 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. +The Vector then had its size *set* to the length of the *zero padded string* -- +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`! 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 put a weird character at the end of the string, sometimes it would just completely crash. +Sometimes it would panic because the string was not `UTF-8`, sometimes it would put a weird character at the end of the string, +sometimes it would just completely crash. ## Disadvantages diff --git a/idioms/ffi-passing-strings.md b/idioms/ffi-passing-strings.md index 246961c1..1e68df78 100644 --- a/idioms/ffi-passing-strings.md +++ b/idioms/ffi-passing-strings.md @@ -85,10 +85,12 @@ pub mod unsafe_module { } ``` -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 created. +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 created. 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 system's ability to return zeroed memory (which is quite fast). +However, recent versions of Rust actually optimize that particular macro to a call to `zmalloc`, +meaning it is as fast as the operating system's ability to return zeroed memory (which is quite fast). ## Disadvantages diff --git a/idioms/index.md b/idioms/index.md index 721ced17..a9f9eed1 100644 --- a/idioms/index.md +++ b/idioms/index.md @@ -1,9 +1,15 @@ # Idioms -[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used styles and patterns largely agreed upon by a community. They are guidelines. Writing idiomatic code allows other developers to understand what is happening because they are familiar with the form that it has. +[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used styles and patterns largely agreed upon by a community. +They are guidelines. +Writing idiomatic code allows other developers to understand what is happening because they are familiar with the form that it has. -The computer understands the machine code that is generated by the compiler. The language is therefore mostly beneficial to the developer. So, since we have this abstraction layer, why not put it to good use and make it simple? +The computer understands the machine code that is generated by the compiler. +The language is therefore mostly beneficial to the developer. +So, since we have this abstraction layer, why not put it to good use and make it simple? -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 kept simple rather than made complicated; therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided". +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 kept simple rather than made complicated; +therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided". > Code is there for humans, not computers, to understand. diff --git a/idioms/option-iter.md b/idioms/option-iter.md index f338ab1a..74e7f4a1 100644 --- a/idioms/option-iter.md +++ b/idioms/option-iter.md @@ -2,7 +2,8 @@ ## Description -`Option` can be viewed as a container that contains either zero or one elements. In particular, it implements the `IntoIterator` trait, and as such can be used with generic code that needs such a type. +`Option` can be viewed as a container that contains either zero or one elements. +In particular, it implements the `IntoIterator` trait, and as such can be used with generic code that needs such a type. ## Examples @@ -31,15 +32,20 @@ for logician in logicians.iter().chain(turing.iter()) { } ``` -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. +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. -Also, since `Option` implements `IntoIterator`, it's possible to iterate 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. +Also, since `Option` implements `IntoIterator`, it's possible to iterate 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. ## See also -* [`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()`. +* [`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()`. -* [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) is a version of [`Iterator::flat_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map), specialized to mapping functions which return `Option`. +* [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) is a version of + [`Iterator::flat_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map), specialized to mapping functions which + return `Option`. * The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions for converting an `Option` to a zero- or one-element slice. diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index 56274769..525f6412 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -28,7 +28,8 @@ fn main(s: a::S) { ## Discussion 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. +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 of the fields and use `..` in the pattern, in which case 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. diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 9badae4a..bff240f1 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -43,7 +43,8 @@ impl Connection { ## Example -Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just create a wrapping dummy function which takes them as arguments: +Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just +create a wrapping dummy function which takes them as arguments: ```rust,ignore struct Connection { @@ -67,7 +68,8 @@ impl Connection { } ``` -**Note** in the above example the line `assert!(response.is_ok());` will not actually run while testing because it is inside of a function which is never invoked. +**Note** in the above example the line `assert!(response.is_ok());` will not actually run while testing +because it is inside of a function which is never invoked. ## Advantages @@ -82,5 +84,6 @@ So this pattern is most useful when need `no_run`. With this, you do not need to If assertions are not required this pattern works well. -If they are, an alternative can be to create a public method to create a dummy instance which is annotated with `#[doc(hidden)]` (so that users won't see it). +If they are, an alternative can be to create a public method to create a dummy 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. diff --git a/patterns/builder.md b/patterns/builder.md index c08c4a91..f9348c30 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -102,4 +102,4 @@ as well as the `FooBuilder::new().a().b().build()` style. - [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically implementing this pattern while avoiding the boilerplate. - [Constructor pattern](../idioms/ctor.md) for when construction is simpler. - [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) -- [Builders enable construction of complex values (C-BUILDER)](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) from the Rust API guidelines +- [Construction of complex values](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) diff --git a/patterns/ffi-export.md b/patterns/ffi-export.md index 4a83b165..8df2c1fd 100644 --- a/patterns/ffi-export.md +++ b/patterns/ffi-export.md @@ -14,7 +14,8 @@ When designing APIs in Rust which are exposed to other languages, there are some 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). -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: +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: 1. Make it easy to use in the target language. 2. Avoid the API dictating internal unsafety on the Rust side as much as possible. @@ -30,7 +31,8 @@ The Object-Based API design allows for writing shims that have good memory safet ## Code Example -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. +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. Here is the definition in C, which hopefully should be easy to read for those involved in FFI. The commentary below should help explaining it for those who miss the subtleties. @@ -58,10 +60,12 @@ It is designed to contain internal state, and acts as an entry point for the lib 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*. -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. +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. -The `datum` type was called a "transactional" type above. It is designed to facilitate the exchange of information between the library and its user. +The `datum` type was called a "transactional" type above. +It is designed to facilitate the exchange of information between the library and its user. 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. @@ -77,7 +81,8 @@ The question is, who owns the memory that pointer points to? 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. +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. This may all seem speculative, but this is what a pointer means in C. It means the same thing as Rust: "user defined lifetime." @@ -176,11 +181,13 @@ This bug is a classic. Here's what happens when the iterator returns the end-of- 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. +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! 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". +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". 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. @@ -209,7 +216,8 @@ Many of the easier design points have other patterns associated with them: - [FFI Error Passing](../idioms/ffi-errors.md) explains error handling with integer codes and sentinel return values (such as `NULL` pointers) -- [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) +- [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) 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. diff --git a/patterns/ffi-wrappers.md b/patterns/ffi-wrappers.md index f761fe12..4bd43c62 100644 --- a/patterns/ffi-wrappers.md +++ b/patterns/ffi-wrappers.md @@ -13,7 +13,8 @@ In Rust, a pointer means "the user manages the lifetime of the pointee." It is t 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. -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. +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. ## Code Example @@ -62,11 +63,13 @@ See [Object-Based APIs](./ffi-export.md) for more on the advantages and pitfalls Often, wrapping types is quite difficult, and sometimes a Rust API compromise would make things easier. 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. +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. ### Trying to Wrap Iterators (and Failing) -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. +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. Suffice it to say, this is *incredibly* difficult. @@ -86,7 +89,8 @@ struct MySetWrapper { 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`*. -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. +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. A simple implementation of `myset_store` would be: @@ -134,5 +138,6 @@ Rust would rather make everything memory safe all the time, for both safety and Being denied access to certain shortcuts is the price Rust programmers need to pay. [^1]: For the C programmers out there scratching their heads, the iterator need not be read *during* this code 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. + 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. diff --git a/patterns/index.md b/patterns/index.md index eada5b8d..c517c28a 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -1,21 +1,29 @@ # Design Patterns -[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 some of the culture and 'tribal knowledge' of programming in a 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. +[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 some of the culture and 'tribal knowledge' +of programming in a 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. -If overused, design patterns can add unnecessary complexity to programs. However, they are a great way to share intermediate and advanced level knowledge about a programming language. +If overused, design patterns can add unnecessary complexity to programs. +However, they are a great way to share intermediate and advanced level knowledge about a programming language. ## Design patterns in Rust -Rust has many very unique features. These features give us great benefit by removing whole classes of problems. Some of them are also patterns that are _unique_ to Rust. +Rust has many very unique features. These features give us great benefit by removing whole classes of problems. +Some of them are also patterns that are _unique_ to Rust. ## YAGNI -If you're not familiar with it, YAGNI is an acronym that stands for `You Aren't Going to Need It`. It's an important software design principle to apply as you write code. +If you're not familiar with it, YAGNI is an acronym that stands for `You Aren't Going to Need It`. +It's an important software design principle to apply as you write code. > The best code I ever wrote was code I never wrote. -If we apply YAGNI to design patterns, we see that the features of Rust allow 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). +If we apply YAGNI to design patterns, we see that the features of Rust allow 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). TODO: Maybe include some code to illustrate the traits. diff --git a/patterns/newtype.md b/patterns/newtype.md index 8eadde3a..fbc0b246 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -94,7 +94,9 @@ most common uses, but they can be used for other reasons: pub struct Foo(Bar); ``` -Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. +Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. ## See also diff --git a/patterns/small-crates.md b/patterns/small-crates.md index 5cfb3780..bb9a6de0 100644 --- a/patterns/small-crates.md +++ b/patterns/small-crates.md @@ -19,7 +19,8 @@ We should take advantage of this tooling, and use smaller, more fine-grained dep * 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`. + 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`. * Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious. * Two small crates may be less optimized than one large one, since the compiler does not perform link-time optimization (LTO) by default. diff --git a/refactoring/index.md b/refactoring/index.md index d5490224..6b539a55 100644 --- a/refactoring/index.md +++ b/refactoring/index.md @@ -1,8 +1,11 @@ # Refactoring -Refactoring is very important in relation to these topics. Just as important as the other topics covered here, is how to take good code and turn it into great code. +Refactoring is very important in relation to these topics. +Just as important as the other topics covered here, is how to take good code and turn it into great code. -We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. While they may be tempting to employ, their costs outweigh their benefits. +We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize abstractions. +We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. +While they may be tempting to employ, their costs outweigh their benefits. > Shortcuts make for long days. From 22e8405b26cf55aa576a5677a4869d2fe7e2a643 Mon Sep 17 00:00:00 2001 From: Ped Date: Sat, 9 Jan 2021 14:42:15 +0100 Subject: [PATCH 086/217] Fix typo ("anways" to "anyways") (#193) --- idioms/coercion-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index f7bb680f..e4a66dc1 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -71,7 +71,7 @@ Curious: true ``` 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 anways (as we did when we used `"Ferris"`). +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`. Let's now take an example where someone gives us a sentence, and we want to determine if any of the words From 264cddf06e109a9e82226d2f40cd157a0570e525 Mon Sep 17 00:00:00 2001 From: Ped Date: Sat, 9 Jan 2021 18:49:11 +0100 Subject: [PATCH 087/217] Fix typo ("desctructors" to "destructors") (#195) --- idioms/dtor-finally.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index 95436fa0..9c6b0374 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -81,7 +81,7 @@ in a function being called. If a destructor panics while unwinding, there is no good action to take, so Rust aborts the thread immediately, without running further destructors. This means -that desctructors are not absolutely guaranteed to run. It also means that you +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. From 497e56e9f78fa2a205a7eaf97dabe620d1dc2ee5 Mon Sep 17 00:00:00 2001 From: Bayram Date: Tue, 12 Jan 2021 04:04:25 +0400 Subject: [PATCH 088/217] Adding Strategy pattern (#146) --- .gitignore | 1 + SUMMARY.md | 1 + patterns/strategy.md | 176 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 patterns/strategy.md diff --git a/.gitignore b/.gitignore index 851a43b9..29b71da3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ # Generated output of mdbook /book +.DS_Store diff --git a/SUMMARY.md b/SUMMARY.md index 7a97dde8..ebf4c6fb 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -31,6 +31,7 @@ - [Newtype](./patterns/newtype.md) - [RAII Guards](./patterns/RAII.md) - [Prefer Small Crates](./patterns/small-crates.md) + - [Strategy](./patterns/strategy.md) - [Contain unsafety in small modules](./patterns/unsafe-mods.md) - [Visitor](./patterns/visitor.md) diff --git a/patterns/strategy.md b/patterns/strategy.md new file mode 100644 index 00000000..9dc5d65a --- /dev/null +++ b/patterns/strategy.md @@ -0,0 +1,176 @@ +# Strategy (aka Policy) + +## Description + +The [Strategy design pattern](https://en.wikipedia.org/wiki/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). + +The basic idea behind the Strategy pattern is that, given an algorithm 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. + +In this way, a client using the algorithm may choose a specific 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". + +## Motivation + +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 completly new format, +or just modify one of the existing formats. + +## Example + +In this example our invariants (or abstractions) are `Context`, `Formatter`, and `Report`, +while `Text` and `Json` are our strategy structs. +These strategies have to implement the `Formatter` trait. + +```rust +use std::collections::HashMap; +type Data = HashMap; + +trait Formatter { + fn format(&self, data: &Data, s: &mut String); +} + +struct Report; + +impl Report { + fn generate(g: T, s: &mut String) { + // backend operations... + let mut data = HashMap::new(); + data.insert("one".to_string(), 1); + data.insert("two".to_string(), 2); + // generate report + g.format(&data, s); + } +} + +struct Text; +impl Formatter for Text { + fn format(&self, data: &Data, s: &mut String) { + *s = data + .iter() + .map(|(key, val)| format!("{} {}\n", key, val)) + .collect(); + } +} + +struct Json; +impl Formatter for Json { + fn format(&self, data: &Data, s: &mut String) { + *s = String::from("["); + let mut iter = data.into_iter(); + if let Some((key, val)) = iter.next() { + let entry = format!(r#"{{"{}":"{}"}}"#, key, val); + s.push_str(&entry); + while let Some((key, val)) = iter.next() { + s.push(','); + let entry = format!(r#"{{"{}":"{}"}}"#, key, val); + s.push_str(&entry); + } + } + s.push(']'); + } +} + +fn main() { + let mut s = String::from(""); + Report::generate(Text, &mut s); + assert!(s.contains("one 1")); + assert!(s.contains("two 2")); + + Report::generate(Json, &mut s); + assert!(s.contains(r#"{"one":"1"}"#)); + assert!(s.contains(r#"{"two":"2"}"#)); +} +``` + +## Advantages + +The main advantage is separation of concerns. For example, in this case `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 context and a specific trait and method to implement, +i.e,`Formatter` and `run`. + +## Disadvantages + +For each strategy there must be implemented at least one module, so number 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. + +## Discussion + +In the previous example all strategies are implemented in a single file. +Ways of providing different strategies includes: + +- All in one file (as shown in this example, similar to being separated as modules) +- Separated as modules, E.g. `formatter::json` module, `formatter::text` module +- Use compiler feature flags, E.g. `json` feature, `text` feature +- Separated as crates, E.g. `json` crate, `text` crate + +Serde crate is a good example of the `Strategy` pattern in action. Serde 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. + +However, we don't need to use traits in order to design this pattern in Rust. + +The following toy example demonstrates the idea of the Strategy pattern using Rust +`closures`: + +```rust +struct Adder; +impl Adder { + pub fn add(x: u8, y: u8, f: F) -> u8 + where + F: Fn(u8, u8) -> u8, + { + f(x, y) + } +} + +fn main() { + let arith_adder = |x, y| x + y; + let bool_adder = |x, y| { + if x == 1 || y == 1 { + 1 + } else { + 0 + } + }; + let custom_adder = |x, y| 2 * x + y; + + assert_eq!(9, Adder::add(4, 5, arith_adder)); + assert_eq!(0, Adder::add(0, 0, bool_adder)); + assert_eq!(5, Adder::add(1, 3, custom_adder)); +} + +``` + +In fact, Rust already uses this idea for `Options`'s `map` method: + +```rust +fn main() { + let val = Some("Rust"); + + let len_strategy = |s: &str| s.len(); + assert_eq!(4, val.map(len_strategy).unwrap()); + + let first_byte_strategy = |s: &str| s.bytes().next().unwrap(); + assert_eq!(82, val.map(first_byte_strategy).unwrap()); +} +``` + +## See also + +- [Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern) +- [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) +- [Policy Based Design](https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design) From f78e3e316600a6890a72e73e4d745fc6069df754 Mon Sep 17 00:00:00 2001 From: vent Date: Wed, 13 Jan 2021 22:08:00 +0000 Subject: [PATCH 089/217] Talk about mem::take instead of mem::replace (#200) * Talk about std::take instead of std::replace * Mention mem::replace in mem::take idiom * Fix example code so it can compile and execute * Clarify the need for Default in disadvantages * Update idioms/mem-take.md * Add note tag to section on mem::replace Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> * Follow on from previous paragraph in mem::take * Change title to include mem::take Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- SUMMARY.md | 2 +- idioms/mem-replace.md | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index ebf4c6fb..e2677532 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,7 +8,7 @@ - [The `Default` Trait](./idioms/default.md) - [Collections Are Smart Pointers](./idioms/deref.md) - [Finalisation in Destructors](./idioms/dtor-finally.md) - - [`mem::replace(_)`](./idioms/mem-replace.md) + - [`mem::{take(_), replace(_)}`](./idioms/mem-replace.md) - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) - [Foreign function interface usage](./idioms/ffi-intro.md) - [Idiomatic Errors](./idioms/ffi-errors.md) diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index b1273168..49d6891b 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -1,4 +1,4 @@ -# `mem::replace` to keep owned values in changed enums +# `mem::{take(_), replace(_)}` to keep owned values in changed enums ## Description @@ -29,7 +29,7 @@ fn a_to_b(e: &mut MyEnum) { // (note that empty strings don't allocate). // Then, construct the new enum variant (which will // be assigned to `*e`, because it is the result of the `if let` expression). - MyEnum::B { name: mem::replace(name, String::new()) } + MyEnum::B { name: mem::take(name) } // In all other cases, we return immediately, thus skipping the assignment } else { return } @@ -38,7 +38,7 @@ fn a_to_b(e: &mut MyEnum) { This also works with more variants: -```Rust +```rust use std::mem; enum MultiVariateEnum { @@ -49,12 +49,12 @@ enum MultiVariateEnum { } fn swizzle(e: &mut MultiVariateEnum) { - use self::MultiVariateEnum::*; + use MultiVariateEnum::*; *e = match *e { // Ownership rules do not allow taking `name` by value, but we cannot // take the value out of a mutable reference, unless we replace it: - A { ref mut name } => B { name: mem::replace(name, String::new()) }, - B { ref mut name } => A { name: mem::replace(name, String::new()) }, + A { ref mut name } => B { name: mem::take(name) }, + B { ref mut name } => A { name: mem::take(name) }, C => D, D => C } @@ -75,10 +75,14 @@ into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy the borrow checker] antipattern. Anyway, we can avoid the extra allocation by changing `e` with only a mutable borrow. -`mem::replace` lets us swap out the value, replacing it with something else. In -this case, we put in an 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. +`mem::take` lets us swap out the value, replacing it with it's default value, +and returning the previous value. For `String`, the default value is an 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. + +__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())`. 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 @@ -95,6 +99,10 @@ 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. +Furthermore, the type you are taking needs to implement the [`Default` +trait](./default.md). However, if the type you're working with doesn't +implement this, you can instead use `mem::replace`. + ## Discussion This pattern is only of interest in Rust. In GC'd languages, you'd take the From b49851f2b68aad23f005fa64d5db99397f627011 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 14 Jan 2021 22:48:24 +0100 Subject: [PATCH 090/217] CONTRIBUTING: Add style guide (#201) --- CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9fe25bbf..e358431c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,15 @@ Don't forget to add your new article to the `SUMMARY.md` to let it be rendered t Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). +## Style guide + +In order to have a consistent style across the book, we suggest to: + +- Follow the official Rust book's [style guide](https://github.com/rust-lang/book/blob/master/style-guide.md). +- Follow [RFC 1574](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text). Tl;dr: + - Prefer full types name. For example `Option` instead of `Option`. + - Prefer line comments (`//`) over block comments (`/* */`) where applicable. + ## Check the article locally Before submitting the PR launch the commands `mdbook build` to make sure that the book builds and `mdbook test` to make sure that From 9c33b276583acae2100454cfa7f41aff600f8b04 Mon Sep 17 00:00:00 2001 From: Cassandra McCarthy Date: Fri, 15 Jan 2021 16:44:03 -0500 Subject: [PATCH 091/217] Use more inclusive language in some parts (#203) --- idioms/rustdoc-init.md | 17 ++++++++++------- patterns/index.md | 12 ++++++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index bff240f1..f1af72bc 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -2,8 +2,9 @@ ## Description -If a struct takes significant effort to initialize, when writing docs, it can be quicker to wrap your example with a -function which takes the struct as an argument. +If a struct takes significant effort to initialize, when writing docs, it can be +quicker to wrap your example with a helper function which takes the struct as an +argument. ## Motivation @@ -43,8 +44,9 @@ impl Connection { ## Example -Instead of typing all of this boiler plate to create an `Connection` and `Request` it is easier to just -create a wrapping dummy function which takes them as arguments: +Instead of typing all of this boiler plate to create an `Connection` and +`Request` it is easier to just create a wrapping helper function which takes +them as arguments: ```rust,ignore struct Connection { @@ -84,6 +86,7 @@ So this pattern is most useful when need `no_run`. With this, you do not need to If assertions are not required this pattern works well. -If they are, an alternative can be to create a public method to create a dummy 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. +If they are, an alternative can be to create a public method to create a 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. diff --git a/patterns/index.md b/patterns/index.md index c517c28a..4c5793be 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -1,11 +1,11 @@ # Design Patterns -[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 some of the culture and 'tribal knowledge' -of programming in a 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. +[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 +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. If overused, design patterns can add unnecessary complexity to programs. However, they are a great way to share intermediate and advanced level knowledge about a programming language. From ceefb9a2ab82de827f92b0d0d313ad995ed34b9c Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 17 Jan 2021 09:48:02 +0100 Subject: [PATCH 092/217] Intro: minor change (#204) --- intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intro.md b/intro.md index 93dd06fb..a25ec6b7 100644 --- a/intro.md +++ b/intro.md @@ -2,7 +2,7 @@ ## Participation -If you are interested in contributing to the Patterns catalogue, check out the +If you are interested in contributing to this book, check out the [contribution guidelines](https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md). ## Design patterns From bfbc505af29f0d331256aab8dbca5f2445a64eec Mon Sep 17 00:00:00 2001 From: Dale Vaillancourt Date: Sun, 17 Jan 2021 13:22:07 -0500 Subject: [PATCH 093/217] Fix spelling of Barbara Liskov's name (#205) Liscov -> Liskov --- additional_resources/design-principles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/additional_resources/design-principles.md b/additional_resources/design-principles.md index c002fdfc..9bcfbc19 100644 --- a/additional_resources/design-principles.md +++ b/additional_resources/design-principles.md @@ -11,7 +11,7 @@ specification should be able to affect the specification of the class. - [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." -- [Liscov Substitution Principle (LSP)](https://en.wikipedia.org/wiki/Liskov_substitution_principle): +- [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." - [Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/Interface_segregation_principle): From c41be87c4565903979f72be909513b4d88e49ee0 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 20 Jan 2021 16:16:12 +0100 Subject: [PATCH 094/217] Create separated page in functional programming (#184) --- SUMMARY.md | 1 + functional/index.md | 72 +++++------------------------------------ functional/paradigms.md | 66 +++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 64 deletions(-) create mode 100644 functional/paradigms.md diff --git a/SUMMARY.md b/SUMMARY.md index e2677532..9128dba8 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -40,6 +40,7 @@ - [Deref Polymorphism](./anti_patterns/deref.md) - [Functional Programming](./functional/index.md) + - [Programming paradigms](./functional/paradigms.md) - [Additional Resources](./additional_resources/index.md) - [Design principles](./additional_resources/design-principles.md) diff --git a/functional/index.md b/functional/index.md index eeab41bd..b29e9caf 100644 --- a/functional/index.md +++ b/functional/index.md @@ -1,66 +1,10 @@ # Functional Usage of Rust -Rust is an imperative language, but it follows many functional programming paradigms. -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. - -## Imperative - -```rust -let mut sum = 0; -for i in 1..11 { - sum += i; -} -println!("{}", sum); -``` - -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. - -| `i` | `sum` | -|:---:|:-----:| -| 1 | 1 | -| 2 | 3 | -| 3 | 6 | -| 4 | 10 | -| 5 | 15 | -| 6 | 21 | -| 7 | 28 | -| 8 | 36 | -| 9 | 45 | -| 10 | 55 | - -This is how most of us start out programming. We learn that a program is a set of steps. - -## Declarative - -```rust -println!("{}", (1..11).fold(0, |a, b| a + b)); -``` - -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. - -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`. - -| `a` | `b` | result | -|:---:|:---:|:------:| -| 0 | 1 | 1 | -| 1 | 2 | 3 | -| 3 | 3 | 6 | -| 6 | 4 | 10 | -| 10 | 5 | 15 | -| 15 | 6 | 21 | -| 21 | 7 | 28 | -| 28 | 8 | 36 | -| 36 | 9 | 45 | -| 45 | 10 | 55 | +Rust is an imperative language, but it follows many +[functional programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms. + +> 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. diff --git a/functional/paradigms.md b/functional/paradigms.md new file mode 100644 index 00000000..3107f755 --- /dev/null +++ b/functional/paradigms.md @@ -0,0 +1,66 @@ +# Programming paradigms + +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. + +## Imperative + +```rust +let mut sum = 0; +for i in 1..11 { + sum += i; +} +println!("{}", sum); +``` + +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. + +| `i` | `sum` | +|:---:|:-----:| +| 1 | 1 | +| 2 | 3 | +| 3 | 6 | +| 4 | 10 | +| 5 | 15 | +| 6 | 21 | +| 7 | 28 | +| 8 | 36 | +| 9 | 45 | +| 10 | 55 | + +This is how most of us start out programming. We learn that a program is a set of steps. + +## Declarative + +```rust +println!("{}", (1..11).fold(0, |a, b| a + b)); +``` + +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. + +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`. + +| `a` | `b` | result | +|:---:|:---:|:------:| +| 0 | 1 | 1 | +| 1 | 2 | 3 | +| 3 | 3 | 6 | +| 6 | 4 | 10 | +| 10 | 5 | 15 | +| 15 | 6 | 21 | +| 21 | 7 | 28 | +| 28 | 8 | 36 | +| 36 | 9 | 45 | +| 45 | 10 | 55 | From 4a7094963a24363a092d9c1da747867b76464daa Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 20 Jan 2021 16:18:41 +0100 Subject: [PATCH 095/217] intro: improve formatting (#206) --- intro.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/intro.md b/intro.md index a25ec6b7..6606eb94 100644 --- a/intro.md +++ b/intro.md @@ -15,17 +15,18 @@ All of these solutions work together to solve a bigger problem. ## Design patterns in Rust There are many problems that share the same form. -Due to the fact that Rust is not object-oriented design patterns vary with respect to other object-oriented programming languages. -While the details are different, since they have the same form they can be solved using the same fundamental methods. - -[Design patterns](./patterns/index.md) are methods to solve common problems when writing software. - -[Anti-patterns](./anti_patterns/index.md) are methods to solve these same common problems. - -However, while design patterns give us benefits, anti-patterns create more problems. - -[Idioms](./idioms/index.md) are guidelines to follow when coding. -They are social norms of the community. -You can break them, but if you do you should have a good reason for it. +Due to the fact that Rust is not object-oriented design patterns vary with +respect to other object-oriented programming languages. +While the details are different, since they have the same form they can be +solved using the same fundamental methods: + +- [Design patterns](./patterns/index.md) are methods to solve common problems + when writing software. +- [Anti-patterns](./anti_patterns/index.md) are methods to solve these same + common problems. However, while design patterns give us benefits, + anti-patterns create more problems. +- [Idioms](./idioms/index.md) are guidelines to follow when coding. + They are social norms of the community. + You can break them, but if you do you should have a good reason for it. TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker From 40d26477a7720c963c47b4016fee4a1a3c877ec4 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Thu, 21 Jan 2021 15:00:00 +0100 Subject: [PATCH 096/217] Updating mdbook to v0.4.6 (#209) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 4de2aeff..5cbca006 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.5 +MDBOOK_VERSION=0.4.6 From 2cd70a552d7f74df243e7243733e498efff1ce1d Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 22 Jan 2021 00:00:02 +0100 Subject: [PATCH 097/217] Shorten lines to line-length 80 (#208) --- .markdownlint.yaml | 2 +- CONTRIBUTING.md | 74 ++++++---- README.md | 25 ++-- additional_resources/design-principles.md | 81 ++++++----- additional_resources/index.md | 9 +- anti_patterns/index.md | 11 +- functional/paradigms.md | 27 ++-- idioms/coercion-arguments.md | 53 +++++--- idioms/ctor.md | 8 +- idioms/ffi-accepting-strings.md | 37 +++-- idioms/ffi-errors.md | 17 ++- idioms/ffi-intro.md | 6 +- idioms/ffi-passing-strings.md | 34 +++-- idioms/index.md | 17 ++- idioms/option-iter.md | 35 +++-- idioms/pass-var-to-closure.md | 15 ++- idioms/priv-extend.md | 28 ++-- idioms/rustdoc-init.md | 14 +- idioms/temporary-mutability.md | 8 +- intro.md | 3 +- patterns/RAII.md | 8 +- patterns/builder.md | 9 +- patterns/compose-structs.md | 3 +- patterns/ffi-export.md | 157 +++++++++++++--------- patterns/ffi-intro.md | 9 +- patterns/ffi-wrappers.md | 93 ++++++++----- patterns/index.md | 18 +-- patterns/newtype.md | 16 ++- patterns/small-crates.md | 35 +++-- patterns/strategy.md | 52 +++---- patterns/unsafe-mods.md | 22 +-- refactoring/index.md | 12 +- 32 files changed, 561 insertions(+), 377 deletions(-) diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 864c1db1..ae89eab5 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -5,7 +5,7 @@ MD003: # Set maximum line length MD013: - line_length: 150 + line_length: 80 # Use `---` for horizontal rule MD035: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e358431c..469d94a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,66 +2,81 @@ ## Introduction -This book is a catalogue of Rust programming techniques, (anti-)patterns, idioms and other explanations. -It is a compilation of collective (sometimes implicit) knowledge as well as experiences that have emerged through collaborative work. +This book is a catalogue of Rust programming techniques, (anti-)patterns, +idioms and other explanations. It is a compilation of collective (sometimes +implicit) knowledge as well as experiences that have emerged through +collaborative work. -The patterns described here are __not rules__, but should be taken as guidelines for writing idiomatic code in Rust. -We are collecting Rust patterns in this book so people can learn the tradeoffs between Rust idioms and use them properly in their own code. +The patterns described here are __not rules__, but should be taken as +guidelines for writing idiomatic code in Rust. We are collecting Rust patterns +in this book so people can learn the tradeoffs between Rust idioms and use them +properly in their own code. If you want to be part of this effort here are some ways you can participate: ## Discussion board -If you have a question or an idea regarding certain content but you want to have feedback of fellow community members -and you think it may not be appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). +If you have a question or an idea regarding certain content but you want to +have feedback of fellow community members and you think it may not be +appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). ## Writing a new article -Before writing a new article please check in one of the following resources if there is -an existing discussion or if someone is already working on that topic: +Before writing a new article please check in one of the following resources if +there is an existing discussion or if someone is already working on that topic: - [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116), - [All issues](https://github.com/rust-unofficial/patterns/issues), - [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) -If you don't find an issue regarding your topic and you are sure it is not more feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) -please open a new issue, so we can discuss about the ideas and future content of the article together and maybe -give some feedback/input on it. +If you don't find an issue regarding your topic and you are sure it is not more +feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) +please open a new issue, so we can discuss about the ideas and future content +of the article together and maybe give some feedback/input on it. -When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) into the -appropriate directory and start editing it. You may not want to fill out every section and remove it or you might want to add extra sections. +When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) +into the appropriate directory and start editing it. You may not want to fill +out every section and remove it or you might want to add extra sections. -Consider writing your article in a way that has a low barrier of entry so also [Rustlings](https://github.com/rust-lang/rustlings) can follow -and understand the thought process behind it. So we can encourage people to use these patterns early on. +Consider writing your article in a way that has a low barrier of entry so also +[Rustlings](https://github.com/rust-lang/rustlings) can follow and understand +the thought process behind it. So we can encourage people to use these patterns +early on. We encourage you to write idiomatic Rust code that builds in the [playground](https://play.rust-lang.org/). -If you use links to blogposts or in general content that is not to be sure existing in a few years (e.g. pdfs) please take a snapshot -with the [Wayback Machine](https://web.archive.org/) and use the link to that snapshot in your article. +If you use links to blogposts or in general content that is not to be sure +existing in a few years (e.g. pdfs) please take a snapshot with the +[Wayback Machine](https://web.archive.org/) and use the link to that snapshot +in your article. -Don't forget to add your new article to the `SUMMARY.md` to let it be rendered to the book. +Don't forget to add your new article to the `SUMMARY.md` to let it be rendered +to the book. -Please make `Draft Pull requests` early so we can follow your progress and can give early feedback (see the following section). +Please make `Draft Pull requests` early so we can follow your progress and can +give early feedback (see the following section). ## Style guide In order to have a consistent style across the book, we suggest to: - Follow the official Rust book's [style guide](https://github.com/rust-lang/book/blob/master/style-guide.md). -- Follow [RFC 1574](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text). Tl;dr: +- Follow [RFC 1574](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text). + Tl;dr: - Prefer full types name. For example `Option` instead of `Option`. - Prefer line comments (`//`) over block comments (`/* */`) where applicable. ## Check the article locally -Before submitting the PR launch the commands `mdbook build` to make sure that the book builds and `mdbook test` to make sure that -code examples are correct. +Before submitting the PR launch the commands `mdbook build` to make sure that +the book builds and `mdbook test` to make sure that code examples are correct. ### Markdown lint To make sure the files comply with our Markdown style we use [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). -To spare you some manual work to get through the CI test you can use the following commands to automatically fix -most of the emerging problems when writing Markdown files. +To spare you some manual work to get through the CI test you can use the +following commands to automatically fix most of the emerging problems when +writing Markdown files. - Install: @@ -81,13 +96,16 @@ most of the emerging problems when writing Markdown files. "Release early and often!" also applies to pull requests! -Once your article has some visible work, create a `[WIP]` draft pull request and give it a description of what you did or want to do. -Early reviews of the community are not meant as an offense but to give feedback. +Once your article has some visible work, create a `[WIP]` draft pull request +and give it a description of what you did or want to do. Early reviews of the +community are not meant as an offense but to give feedback. A good principle: "Work together, share ideas, teach others." ### Important Note -Please **don't force push** commits in your branch, in order to keep commit history and make it easier for us to see changes between reviews. +Please **don't force push** commits in your branch, in order to keep commit +history and make it easier for us to see changes between reviews. -Make sure to `Allow edits of maintainers` (under the text box) in the PR so people can actually collaborate on things or fix smaller issues themselves. +Make sure to `Allow edits of maintainers` (under the text box) in the PR so +people can actually collaborate on things or fix smaller issues themselves. diff --git a/README.md b/README.md index 422d2f8c..76c5b8e9 100644 --- a/README.md +++ b/README.md @@ -5,28 +5,33 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). ## Contributing -You are missing content in this repository that can be helpful for others and you are eager to explain it? -Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. +You are missing content in this repository that can be helpful for others and +you are eager to explain it? Awesome! We are always happy about new contributions +(e.g. elaboration or corrections on certain topics) to this project. -You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) for all the -patterns, anti-patterns, and idioms that could be added. +You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) +for all the patterns, anti-patterns, and idioms that could be added. -We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information on how contributing to this repository works. +We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information +on how contributing to this repository works. ## Building with mdbook -This book is built with [mdbook](https://rust-lang.github.io/mdBook/). You can install it by running `cargo install mdbook`. +This book is built with [mdbook](https://rust-lang.github.io/mdBook/). You can +install it by running `cargo install mdbook`. -If you want to build it locally you can run one of these two commands in the root directory of the repository: +If you want to build it locally you can run one of these two commands in the root +directory of the repository: - `mdbook build` - Builds static html pages as output and place them in the `/book` directory by default. + Builds static html pages as output and place them in the `/book` directory by + default. - `mdbook serve` - Serves the book at `http://localhost:3000` (port is changeable, take a look at the terminal output - to be sure) and reloads the browser when a change occurs. + Serves the book at `http://localhost:3000` (port is changeable, take a look at + the terminal output to be sure) and reloads the browser when a change occurs. ## License diff --git a/additional_resources/design-principles.md b/additional_resources/design-principles.md index 9bcfbc19..b764d368 100644 --- a/additional_resources/design-principles.md +++ b/additional_resources/design-principles.md @@ -7,80 +7,89 @@ ## [SOLID](https://en.wikipedia.org/wiki/SOLID) - [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. + 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. - [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." + "Software entities ... should be open for extension, but closed for + modification." - [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." + "Objects in a program should be replaceable with instances of their subtypes + without altering the correctness of that program." - [Interface Segregation Principle (ISP)](https://en.wikipedia.org/wiki/Interface_segregation_principle): - "Many client-specific interfaces are better than one general-purpose interface." + "Many client-specific interfaces are better than one general-purpose + interface." - [Dependency Inversion Principle (DIP)](https://en.wikipedia.org/wiki/Dependency_inversion_principle): One should "depend upon abstractions, [not] concretions." ## [DRY (Don’t Repeat Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) -"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system" +"Every piece of knowledge must have a single, unambiguous, authoritative +representation within a system" ## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) -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 +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 ## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter) -a given object should assume as little as possible about the structure or properties of -anything else (including its subcomponents), in accordance with the principle of "information hiding" +a given object should assume as little as possible about the structure or +properties of anything else (including its subcomponents), in accordance with +the principle of "information hiding" ## [Design by contract (DbC)](https://en.wikipedia.org/wiki/Design_by_contract) -software designers should define formal, precise and verifiable interface specifications -for software components, which extend the ordinary definition of abstract data types with -preconditions, postconditions and invariants +software designers should define formal, precise and verifiable interface +specifications for software components, which extend the ordinary definition of +abstract data types with preconditions, postconditions and invariants ## [Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) -bundling of data with the methods that operate on that data, or the 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. +bundling of data with the methods that operate on that data, or the 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. ## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) -“Functions should not produce abstract side effects...only commands (procedures) will -be permitted to produce side effects.” - Bertrand Meyer: Object Oriented Software Construction +“Functions should not produce abstract side effects...only commands +(procedures) will be permitted to produce side effects.” - Bertrand Meyer: +Object Oriented Software Construction ## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) -a component of a system should behave in a way that most users will expect it to behave. -The behavior should not astonish or surprise users +a component of a system should behave in a way that most users will expect it +to behave. The behavior should not astonish or surprise users ## Linguistic-Modular-Units -“Modules must correspond to syntactic units in the language used.” - Bertrand Meyer: -Object Oriented Software Construction +“Modules must correspond to syntactic units in the language used.” - Bertrand +Meyer: Object Oriented Software Construction ## Self-Documentation -“The designer of a module should strive to make all information about the module part of -the module itself.” - Bertrand Meyer: Object Oriented Software Construction +“The designer of a module should strive to make all information about the +module part of the module itself.” - Bertrand Meyer: Object Oriented Software +Construction ## Uniform-Access -“All services offered by a module should be available through a uniform notation, -which does not betray whether they are implemented through storage or through computation.” - -Bertrand Meyer: Object Oriented Software Construction +“All services offered by a module should be available through a uniform +notation, which does not betray whether they are implemented through storage or +through computation.” - Bertrand Meyer: Object Oriented Software Construction ## Single-Choice -“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: Object Oriented -Software Construction +“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: +Object Oriented Software Construction ## Persistence-Closure -“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 +“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 diff --git a/additional_resources/index.md b/additional_resources/index.md index 0ee43775..29022937 100644 --- a/additional_resources/index.md +++ b/additional_resources/index.md @@ -4,9 +4,12 @@ A collection of complementary helpful content ## Talks -- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by Nicholas Cameron at the PDRust (2016) -- [Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?v=0zOg8_B71gE) by Pascal Hertleif at RustFest (2017) -- [Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) by Nicholas Cameron at LinuxConfAu (2018) +- [Design Patterns in Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) by + Nicholas Cameron at the PDRust (2016) +- [Writing Idiomatic Libraries in Rust](https://www.youtube.com/watch?v=0zOg8_B71gE) + by Pascal Hertleif at RustFest (2017) +- [Rust Programming Techniques](https://www.youtube.com/watch?v=vqavdUGKeb4) by + Nicholas Cameron at LinuxConfAu (2018) ## Books (Online) diff --git a/anti_patterns/index.md b/anti_patterns/index.md index 5df2acb0..84107e04 100644 --- a/anti_patterns/index.md +++ b/anti_patterns/index.md @@ -1,7 +1,8 @@ # Anti-patterns -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. +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. diff --git a/functional/paradigms.md b/functional/paradigms.md index 3107f755..9fc3b99e 100644 --- a/functional/paradigms.md +++ b/functional/paradigms.md @@ -1,8 +1,9 @@ # Programming paradigms -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. +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. ## Imperative @@ -33,7 +34,8 @@ Then we print it out. | 9 | 45 | | 10 | 55 | -This is how most of us start out programming. We learn that a program is a set of steps. +This is how most of us start out programming. We learn that a program is a set +of steps. ## Declarative @@ -42,15 +44,16 @@ println!("{}", (1..11).fold(0, |a, b| a + b)); ``` 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. +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. -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`. +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`. | `a` | `b` | result | |:---:|:---:|:------:| diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index e4a66dc1..89e29f8b 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -2,24 +2,30 @@ ## Description -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. +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. 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__. +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`. -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 `String` has a layer of indirection, so a `&String` will have two layers of indrection. -We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. +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 +`String` has a layer of indirection, so a `&String` will have two layers of +indrection. We can avoid this by using `&str` instead, and letting `&String` +coerce to a `&str` whenever the function is invoked. ## Example -For this example, we will illustrate some differences for using `&String` as a function argument versus using a `&str`, -but the ideas apply as well to using `&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. +For this example, we will illustrate some differences for using `&String` as a +function argument versus using a `&str`, but the ideas apply as well to using +`&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. -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. +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. The code might look something like this: @@ -54,8 +60,9 @@ fn main() { ``` This works fine because we are passing a `&String` type as a parameter. -If we comment in the last two lines this example fails because a `&str` type will not coerce to a `&String` type. -We can fix this by simply modifying the type for our argument. +If we comment in the last two lines this example fails because a `&str` type +will not coerce to a `&String` type. We can fix this by simply modifying the +type for our argument. For instance, if we change our function declaration to: @@ -71,12 +78,16 @@ Curious: true ``` 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`. +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`. -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 has a word that contains three consecutive vowels. -We probably should make use of the function we have already defined and simply feed in each word from the sentence. +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 has a word that contains three +consecutive vowels. +We probably should make use of the function we have already defined and simply +feed in each word from the sentence. An example of this could look like this: @@ -108,15 +119,17 @@ fn main() { } ``` -Running this example using our function declared with an argument type `&str` will yield +Running this example using our function declared with an argument type `&str` +will yield ```bash curious has three consecutive vowels! ``` -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 `&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. +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 +`&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. ## See also diff --git a/idioms/ctor.md b/idioms/ctor.md index 56ff212d..aef2aaef 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -2,8 +2,8 @@ ## Description -Rust does not have constructors as a language construct. Instead, the convention -is to use a static `new` method to create an object. +Rust does not have constructors as a language construct. Instead, the +convention is to use a static `new` method to create an object. ## Example @@ -32,5 +32,5 @@ impl Vec { ## See also -The [builder pattern](../patterns/builder.md) for constructing objects where there are multiple -configurations. +The [builder pattern](../patterns/builder.md) for constructing objects where +there are multiple configurations. diff --git a/idioms/ffi-accepting-strings.md b/idioms/ffi-accepting-strings.md index 6dd5af9d..98f364d4 100644 --- a/idioms/ffi-accepting-strings.md +++ b/idioms/ffi-accepting-strings.md @@ -2,18 +2,21 @@ ## Description -When accepting strings via FFI through pointers, there are two principles that should be followed: +When accepting strings via FFI through pointers, there are two principles that +should be followed: 1. Keep foreign strings "borrowed", rather than copying them directly. 2. Minimize `unsafe` code during the conversion. ## Motivation -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 are being accepted from a foreign caller of a Rust function. +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 +are being accepted from a foreign caller of a Rust function. -The best practice is simple: use `CStr` in such a way as to minimize unsafe code, and create a borrowed slice. -If an owned String is needed, call `to_string()` on the string slice. +The best practice is simple: use `CStr` in such a way as to minimize unsafe +code, and create a borrowed slice. If an owned String is needed, call +`to_string()` on the string slice. ## Code Example @@ -49,7 +52,8 @@ pub mod unsafe_module { The example is is written to ensure that: 1. The `unsafe` block is as small as possible. -2. The pointer with an "untracked" lifetime becomes a "tracked" shared reference +2. The pointer with an "untracked" lifetime becomes a "tracked" shared + reference Consider an alternative, where the string is actually copied: @@ -59,7 +63,8 @@ pub mod unsafe_module { // other module content pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) { - /* DO NOT USE THIS CODE. IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG. */ + // DO NOT USE THIS CODE. + // IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG. let level: crate::LogLevel = match level { /* ... */ }; @@ -96,20 +101,24 @@ pub mod unsafe_module { This code in inferior to the original in two respects: -1. There is much more `unsafe` code, and more importantly, more invariants it must uphold. -2. Due to the extensive arithmetic required, there is a bug in this version that cases Rust `undefined behaviour`. +1. There is much more `unsafe` code, and more importantly, more invariants it + must uphold. +2. Due to the extensive arithmetic required, there is a bug in this version + that cases Rust `undefined behaviour`. -The bug here is a simple mistake in pointer arithmetic: the string was copied, all `msg_len` bytes of it. -However, the `NUL` terminator at the end was not. +The bug here is a simple mistake in pointer arithmetic: the string was copied, +all `msg_len` bytes of it. However, the `NUL` terminator at the end was not. The Vector then had its size *set* to the length of the *zero padded string* -- 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`! +When the `CString` is created at the bottom of the block, its read of the +Vector will cause `undefined behaviour`! 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 put a weird character at the end of the string, -sometimes it would just completely crash. +Sometimes it would panic because the string was not `UTF-8`, sometimes it would +put a weird character at the end of the string, sometimes it would just +completely crash. ## Disadvantages diff --git a/idioms/ffi-errors.md b/idioms/ffi-errors.md index 3bdeec41..59d0c912 100644 --- a/idioms/ffi-errors.md +++ b/idioms/ffi-errors.md @@ -3,12 +3,15 @@ ## Description 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 a propogated through a full type. +However, Rust's type system allows much more rich error information to be +captured a propogated through a full type. -This best practice shows different kinds of error codes, and how to expose them in a usable way: +This best practice shows different kinds of error codes, and how to expose them +in a usable way: 1. Flat Enums should be converted to integers and returned as codes. -2. Structured Enums should be converted to an integer code with a string error message for detail. +2. Structured Enums should be converted to an integer code with a string error + message for detail. 3. Custom Error Types should become "transparent", with a C representation. ## Code Example @@ -59,7 +62,7 @@ pub mod c_api { ) -> *mut libc::c_char { let error: &DatabaseError = unsafe { - /* SAFETY: pointer lifetime is greater than the current stack frame */ + // SAFETY: pointer lifetime is greater than the current stack frame &*e }; @@ -127,8 +130,10 @@ impl From for parse_error { ## Advantages -This ensures that the foreign language has clear access to error information while not compromising the Rust code's API at all. +This ensures that the foreign language has clear access to error information +while not compromising the Rust code's API at all. ## Disadvantages -It's a lot of typing, and some types may not be able to be converted easily to C. +It's a lot of typing, and some types may not be able to be converted easily +to C. diff --git a/idioms/ffi-intro.md b/idioms/ffi-intro.md index 9c58b744..26fc542a 100644 --- a/idioms/ffi-intro.md +++ b/idioms/ffi-intro.md @@ -1,11 +1,13 @@ # FFI Idioms 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. +However, there are several idioms here that can act as pointers, and avoid +traps for inexperienced users of `unsafe` Rust. This section contains idioms that may be useful when doing FFI. -1. [Idiomatic Errors](./ffi-errors.md) - Error handling with integer codes and sentinel return values (such as `NULL` pointers) +1. [Idiomatic Errors](./ffi-errors.md) - Error handling with integer codes and + sentinel return values (such as `NULL` pointers) 2. [Accepting Strings](./ffi-accepting-strings.md) with minimal unsafe code diff --git a/idioms/ffi-passing-strings.md b/idioms/ffi-passing-strings.md index 1e68df78..e7457726 100644 --- a/idioms/ffi-passing-strings.md +++ b/idioms/ffi-passing-strings.md @@ -2,21 +2,26 @@ ## Description -When passing strings to FFI functions, there are four principles that should be followed: +When passing strings to FFI functions, there are four principles that should be +followed: 1. Make the lifetime of owned strings as long as possible. 2. Minimize `unsafe` code during the conversion. 3. If the C code can modify the string data, use `Vec` instead of `CString`. -4. Unless the Foreign Function API requires it, the ownership of the string should not transfer to the callee. +4. Unless the Foreign Function API requires it, the ownership of the string + should not transfer to the callee. ## Motivation -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 are being sent to a foreign function call from a Rust function. +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 +are being sent to a foreign function call from a Rust function. -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. +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. ## Code Example @@ -68,7 +73,8 @@ The example is written in a way to ensure that: 2. The `CString` lives long enough. 3. Errors with typecasts are always propagated when possible. -A common mistake (so common it's in the documentation) is to not use the variable in the first block: +A common mistake (so common it's in the documentation) is to not use the +variable in the first block: ```rust,ignore pub mod unsafe_module { @@ -85,12 +91,14 @@ pub mod unsafe_module { } ``` -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 created. +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 +created. -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 system's ability to return zeroed memory (which is quite fast). +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 +system's ability to return zeroed memory (which is quite fast). ## Disadvantages diff --git a/idioms/index.md b/idioms/index.md index a9f9eed1..e03fcfa0 100644 --- a/idioms/index.md +++ b/idioms/index.md @@ -1,15 +1,18 @@ # Idioms -[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used styles and patterns largely agreed upon by a community. -They are guidelines. -Writing idiomatic code allows other developers to understand what is happening because they are familiar with the form that it has. +[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used +styles and patterns largely agreed upon by a community. They are guidelines. +Writing idiomatic code allows other developers to understand what is happening +because they are familiar with the form that it has. The computer understands the machine code that is generated by the compiler. The language is therefore mostly beneficial to the developer. -So, since we have this abstraction layer, why not put it to good use and make it simple? +So, since we have this abstraction layer, why not put it to good use and make +it simple? -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 kept simple rather than made complicated; -therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided". +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 +kept simple rather than made complicated; therefore, simplicity should be a key +goal in design, and unnecessary complexity should be avoided". > Code is there for humans, not computers, to understand. diff --git a/idioms/option-iter.md b/idioms/option-iter.md index 74e7f4a1..e1c74bd0 100644 --- a/idioms/option-iter.md +++ b/idioms/option-iter.md @@ -2,12 +2,14 @@ ## Description -`Option` can be viewed as a container that contains either zero or one elements. -In particular, it implements the `IntoIterator` trait, and as such can be used with generic code that needs such a type. +`Option` can be viewed as a container that contains either zero or one +elements. In particular, it implements the `IntoIterator` trait, and as such +can be used with generic code that needs such a type. ## Examples -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): +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): ```rust let turing = Some("Turing"); @@ -21,7 +23,8 @@ if let Some(turing_inner) = turing { } ``` -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): +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): ```rust let turing = Some("Turing"); @@ -32,21 +35,25 @@ for logician in logicians.iter().chain(turing.iter()) { } ``` -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. +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. -Also, since `Option` implements `IntoIterator`, it's possible to iterate 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. +Also, since `Option` implements `IntoIterator`, it's possible to iterate 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. ## See also -* [`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()`. +* [`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()`. -* [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) is a version of - [`Iterator::flat_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map), specialized to mapping functions which - return `Option`. +* [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) + is a version of [`Iterator::flat_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map), + specialized to mapping functions which return `Option`. -* The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions for converting an `Option` to a zero- or one-element slice. +* The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions + for converting an `Option` to a zero- or one-element slice. * [Documentation for `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) diff --git a/idioms/pass-var-to-closure.md b/idioms/pass-var-to-closure.md index 17c0031b..81e5b51c 100644 --- a/idioms/pass-var-to-closure.md +++ b/idioms/pass-var-to-closure.md @@ -2,9 +2,10 @@ ## Description -By default, closures capture their environment by borrowing. Or you can use `move`-closure -to move whole environment. However, often you want to move just some variables to closure, -give it copy of some data, pass it by reference, or perform some other transformation. +By default, closures capture their environment by borrowing. Or you can use +`move`-closure to move whole environment. However, often you want to move just +some variables to closure, give it copy of some data, pass it by reference, or +perform some other transformation. Use variable rebinding in separate scope for that. @@ -46,10 +47,12 @@ let closure = move || { ## Advantages -Copied data are grouped together with closure definition, so their purpose is more clear -and they will be dropped immediately even if they are not consumed by closure. +Copied data are grouped together with closure definition, so their purpose is +more clear and they will be dropped immediately even if they are not consumed +by closure. -Closure uses same variable names as surrounding code whether data are copied or moved. +Closure uses same variable names as surrounding code whether data are copied or +moved. ## Disadvantages diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index 525f6412..d0c115b6 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -28,15 +28,19 @@ fn main(s: a::S) { ## Discussion 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 of the fields and use `..` in the pattern, in which case 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. - -The downside of this approach is that you might need to add an otherwise 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. - -If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible. -The problem there is exhaustive match expressions. -A private variant would force clients to have a `_` wildcard pattern. -A common way to implement this instead is using the [#[non_exhaustive]](https://doc.rust-lang.org/reference/attributes/type_system.html) attribute. +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 of the fields and use `..` in the pattern, +in which case 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. + +The downside of this approach is that you might need to add an otherwise 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. + +If Rust allowed private variants of enums, we could use the same trick to make +adding a variant to an enum backwards compatible. The problem there is exhaustive +match expressions. A private variant would force clients to have a `_` wildcard +pattern. A common way to implement this instead is using the [`#[non_exhaustive]`]() +attribute. diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index f1af72bc..63f7d1a2 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -8,8 +8,8 @@ argument. ## Motivation -Sometimes there is a struct with multiple or complicated parameters and several methods. -Each of these methods should have examples. +Sometimes there is a struct with multiple or complicated parameters and several +methods. Each of these methods should have examples. For example: @@ -70,8 +70,9 @@ impl Connection { } ``` -**Note** in the above example the line `assert!(response.is_ok());` will not actually run while testing -because it is inside of a function which is never invoked. +**Note** in the above example the line `assert!(response.is_ok());` will not +actually run while testing because it is inside of a function which is never +invoked. ## Advantages @@ -79,8 +80,9 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages -As example is in a function, the code will not be tested. (Though it still will checked to make sure it compiles when running a `cargo test`) -So this pattern is most useful when need `no_run`. With this, you do not need to add `no_run`. +As example is in a function, the code will not be tested. Though it still will +checked to make sure it compiles when running a `cargo test`. So this pattern is +most useful when need `no_run`. With this, you do not need to add `no_run`. ## Discussion diff --git a/idioms/temporary-mutability.md b/idioms/temporary-mutability.md index 94f7eea4..c6d51b3c 100644 --- a/idioms/temporary-mutability.md +++ b/idioms/temporary-mutability.md @@ -2,10 +2,12 @@ ## Description -Often it is necessary to prepare and process some data, but after that data are only inspected -and never modified. The intention can be made explicit by redefining the mutable variable as immutable. +Often it is necessary to prepare and process some data, but after that data are +only inspected and never modified. The intention can be made explicit by redefining +the mutable variable as immutable. -It can be done either by processing data within nested block or by redefining variable. +It can be done either by processing data within nested block or by redefining +variable. ## Example diff --git a/intro.md b/intro.md index 6606eb94..84868411 100644 --- a/intro.md +++ b/intro.md @@ -29,4 +29,5 @@ solved using the same fundamental methods: They are social norms of the community. You can break them, but if you do you should have a good reason for it. -TODO: Mention why Rust is a bit special - functional elements, type system, borrow checker +TODO: Mention why Rust is a bit special - functional elements, type system, +borrow checker diff --git a/patterns/RAII.md b/patterns/RAII.md index 2024d201..d7b6dbfd 100644 --- a/patterns/RAII.md +++ b/patterns/RAII.md @@ -2,10 +2,10 @@ ## Description -[RAII][wikipedia] 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 an RAII object as a guard of some resource and relying +[RAII][wikipedia] 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 an 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. ## Example diff --git a/patterns/builder.md b/patterns/builder.md index f9348c30..ab6a4981 100644 --- a/patterns/builder.md +++ b/patterns/builder.md @@ -33,9 +33,11 @@ impl FooBuilder { } // If we can get away with not consuming the Builder here, that is an - // advantage. It means we can use the FooBuilder as a template for constructing many Foos. + // advantage. It means we can use the FooBuilder as a template for constructing + // many Foos. pub fn build(self) -> Foo { - // Create a Foo from the FooBuilder, applying all settings in FooBuilder to Foo. + // Create a Foo from the FooBuilder, applying all settings in FooBuilder + // to Foo. Foo { bar: self.bar } } } @@ -99,7 +101,8 @@ as well as the `FooBuilder::new().a().b().build()` style. ## See also - [Description in the style guide](https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html) -- [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically implementing this pattern while avoiding the boilerplate. +- [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically + implementing this pattern while avoiding the boilerplate. - [Constructor pattern](../idioms/ctor.md) for when construction is simpler. - [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) - [Construction of complex values](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) diff --git a/patterns/compose-structs.md b/patterns/compose-structs.md index 47e93eac..013f6cb7 100644 --- a/patterns/compose-structs.md +++ b/patterns/compose-structs.md @@ -33,7 +33,8 @@ fn baz(a: &mut A) { // The later usage of x causes a to be borrowed for the rest of the function. let x = foo(a); // Borrow checker error: - // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once at a time + // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once + // at a time println!("{}", x); } ``` diff --git a/patterns/ffi-export.md b/patterns/ffi-export.md index 8df2c1fd..6bb719e5 100644 --- a/patterns/ffi-export.md +++ b/patterns/ffi-export.md @@ -2,40 +2,49 @@ ## Description -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: +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: -1. All Encapsulated types should be *owned* by Rust, *managed* by the user, and *opaque*. +1. All Encapsulated types should be *owned* by Rust, *managed* by the user, + and *opaque*. 2. All Transactional data types should be *owned* by the user, and *transparent*. 3. All library behavior should be functions acting upon Encapsulated types. -4. All library behavior should be encapsulated into types not based on structure, but *provenance/lifetime*. +4. All library behavior should be encapsulated into types not based on structure, + but *provenance/lifetime*. ## Motivation 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). +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). -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: +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: 1. Make it easy to use in the target language. 2. Avoid the API dictating internal unsafety on the Rust side as much as possible. -3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small as possible. +3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small + as possible. -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`. +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`. -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. +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. -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`. +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`. ## Code Example 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. -Here is the definition in C, which hopefully should be easy to read for those involved in FFI. -The commentary below should help explaining it for those who miss the subtleties. +Here is the definition in C, which hopefully should be easy to read for those +involved in FFI. The commentary below should help explaining it for those who +miss the subtleties. ```C struct DBM; @@ -55,54 +64,67 @@ int dbm_store(DBM *, datum, datum, int); This API defines two types: `DBM` and `datum`. 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. +It is designed to contain internal state, and acts as an entry point for the +library's behavior. -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*. +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*. 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. +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. The `datum` type was called a "transactional" type above. -It is designed to facilitate the exchange of information between the library and its user. +It is designed to facilitate the exchange of information between the library and +its user. -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. +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. 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`. +But the library does not care, and by the rules of C casting, any type behind a +pointer can be cast to `void`. -As noted earlier, this type is *transparent* to the user. But also, this type is *owned* by the user. +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? 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. +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. 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 is what this best practice is about, and the key is to *transfer ownership of everything that is transparent*. +That said, there are some decisions that have fewer or greater consequences if users +do it wrong. Minimizing those is what this best practice is about, and the key +is to *transfer ownership of everything that is transparent*. ## Advantages -This minimizes the number of memory safety guarantees the user must uphold to a relatively small number: +This minimizes the number of memory safety guarantees the user must uphold to a +relatively small number: -1. Do not call any function with a pointer not returned by `dbm_open` (invalid access or corruption). +1. Do not call any function with a pointer not returned by `dbm_open` (invalid + access or corruption). 2. Do not call any function on a pointer after close (use after free). -3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of memory at the advertised length. +3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of memory + at the advertised length. In addition, it avoids a lot of pointer provenance issues. To understand why, let us consider an alternative in some depth: key iteration. 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. +When implementing one, the programmer makes a separate type with a bounded lifetime +to its owner, and implements the `Iterator` trait. Here is how iteration would be done in Rust for `DBM`: @@ -128,26 +150,31 @@ However, consider what a straightforward API translation would look like: ```rust,ignore #[no_mangle] pub extern "C" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter { - /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ + // THIS API IS A BAD IDEA! For real applications, use object-based design instead. } #[no_mangle] -pub extern "C" fn dbm_iter_next(iter: *mut DbmKeysIter, key_out: *const datum) -> libc::c_int { - /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ +pub extern "C" fn dbm_iter_next( + iter: *mut DbmKeysIter, + key_out: *const datum +) -> libc::c_int { + // THIS API IS A BAD IDEA! For real applications, use object-based design instead. } #[no_mangle] pub extern "C" fn dbm_iter_del(*mut DbmKeysIter) { - /* THIS API IS A BAD IDEA! For real applications, use object-based design instead. */ + // THIS API IS A BAD IDEA! For real applications, use object-based design instead. } ``` -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. +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. This example written in C contains a bug that will be explained afterwards: ```C int count_key_sizes(DBM *db) { - /* DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG! */ + // DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG! datum key; int len = 0; @@ -172,26 +199,30 @@ int count_key_sizes(DBM *db) { } ``` -This bug is a classic. Here's what happens when the iterator returns the end-of-iteration marker: +This bug is a classic. Here's what happens when the iterator returns the +end-of-iteration marker: 1. The loop condition sets `l` to zero, and enters the loop because `0 >= 0`. 2. The length is incremented, in this case by zero. -3. The if statement is true, so the database is closed. There should be a break statement here. +3. The if statement is true, so the database is closed. There should be a break + statement here. 4. The loop condition executes again, causing a `next` call on the closed object. 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! +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! 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". +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". 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: +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: ```C datum dbm_firstkey(DBM *); @@ -202,22 +233,28 @@ Thus, all of the lifetimes were bound together, and such unsafety was prevented. ## Disadvantages -However, this design choice also has a number of drawbacks, which should be considered as well. +However, this design choice also has a number of drawbacks, which should be +considered as well. 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. +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. -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: +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: -- [Wrapper Type Consolidation](./ffi-wrappers.md) groups multiple Rust types together into an opaque "object" +- [Wrapper Type Consolidation](./ffi-wrappers.md) groups multiple Rust types together + into an opaque "object" -- [FFI Error Passing](../idioms/ffi-errors.md) explains error handling with integer codes and sentinel return values (such as `NULL` pointers) +- [FFI Error Passing](../idioms/ffi-errors.md) explains error handling with integer + codes and sentinel return values (such as `NULL` pointers) -- [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) +- [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) 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. diff --git a/patterns/ffi-intro.md b/patterns/ffi-intro.md index d6d6b192..b2df4bdf 100644 --- a/patterns/ffi-intro.md +++ b/patterns/ffi-intro.md @@ -1,10 +1,13 @@ # FFI Patterns 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. +However, there are several idioms here that can act as pointers, and avoid traps +for inexperienced users of unsafe Rust. This section contains design patterns that may be useful when doing FFI. -1. [Object-Based API](./ffi-export.md) design that has good memory safety characteristics, and a clean boundary of what is safe and what is unsafe +1. [Object-Based API](./ffi-export.md) design that has good memory safety characteristics, + and a clean boundary of what is safe and what is unsafe -2. [Type Consolidation into Wrappers](./ffi-wrappers.md) - group multiple Rust types together into an opaque "object" +2. [Type Consolidation into Wrappers](./ffi-wrappers.md) - group multiple Rust types + together into an opaque "object" diff --git a/patterns/ffi-wrappers.md b/patterns/ffi-wrappers.md index 4bd43c62..7adcf881 100644 --- a/patterns/ffi-wrappers.md +++ b/patterns/ffi-wrappers.md @@ -2,32 +2,39 @@ ## Description -This pattern is designed to allow gracefully handling multiple related types, while minimizing the surface area for memory unsafety. +This pattern is designed to allow gracefully handling multiple related types, +while minimizing the surface area for memory unsafety. 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. +This ensures that many patterns of access between types can be memory safe, +data race safety included. -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. +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. -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. +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. -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. +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. ## Code Example -To understand this, let us look at a classic example of an API to export: iteration through a collection. +To understand this, let us look at a classic example of an API to export: iteration +through a collection. That API looks like this: 1. The iterator is initialized with `first_key`. 2. Each call to `next_key` will advance the iterator. 3. Calls to `next_key` if the iterator is at the end will do nothing. -4. As noted above, the iterator is "wrapped into" the collection (unlike the native Rust API). +4. As noted above, the iterator is "wrapped into" the collection (unlike the native + Rust API). -If the iterator implements `nth()` efficiently, then it is possible to make it ephemeral to each function call: +If the iterator implements `nth()` efficiently, then it is possible to make it +ephemeral to each function call: ```rust,ignore struct MySetWrapper { @@ -56,20 +63,24 @@ As a result, the wrapper is simple and contains no `unsafe` code. ## Advantages This makes APIs safer to use, avoiding issues with lifetimes between types. -See [Object-Based APIs](./ffi-export.md) for more on the advantages and pitfalls this avoids. +See [Object-Based APIs](./ffi-export.md) for more on the advantages and pitfalls +this avoids. ## Disadvantages -Often, wrapping types is quite difficult, and sometimes a Rust API compromise would make things easier. +Often, wrapping types is quite difficult, and sometimes a Rust API compromise +would make things easier. 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. +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. ### Trying to Wrap Iterators (and Failing) -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. +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. Suffice it to say, this is *incredibly* difficult. @@ -86,12 +97,14 @@ struct MySetWrapper { } ``` -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`*. +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`*. -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. +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. A simple implementation of `myset_store` would be: @@ -105,7 +118,7 @@ pub mod unsafe_module { key: datum, value: datum) -> libc::c_int { - /* DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM. */ + // DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM. let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in here! &mut (*myset).myset @@ -121,23 +134,29 @@ pub mod unsafe_module { } ``` -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] +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] 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. +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. 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 has an entire lexicon dedicated to concurrent behavior!](https://manpages.debian.org/buster/manpages/attributes.7.en.html) - -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. - -[^1]: For the C programmers out there scratching their heads, the iterator need not be read *during* this code cause the UB. - The exclusivity rule also enables compiler optimizations which may cause inconsistent observations by the iterator's +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! + +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. + +[^1]: For the C programmers out there scratching their heads, the iterator need + not be read *during* this code 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. diff --git a/patterns/index.md b/patterns/index.md index 4c5793be..1bdda780 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -8,22 +8,24 @@ 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. If overused, design patterns can add unnecessary complexity to programs. -However, they are a great way to share intermediate and advanced level knowledge about a programming language. +However, they are a great way to share intermediate and advanced level knowledge +about a programming language. ## Design patterns in Rust -Rust has many very unique features. These features give us great benefit by removing whole classes of problems. -Some of them are also patterns that are _unique_ to Rust. +Rust has many very unique features. These features give us great benefit by removing +whole classes of problems. Some of them are also patterns that are _unique_ to Rust. ## YAGNI -If you're not familiar with it, YAGNI is an acronym that stands for `You Aren't Going to Need It`. -It's an important software design principle to apply as you write code. +If you're not familiar with it, YAGNI is an acronym that stands for +`You Aren't Going to Need It`. It's an important software design principle to apply +as you write code. > The best code I ever wrote was code I never wrote. -If we apply YAGNI to design patterns, we see that the features of Rust allow 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). +If we apply YAGNI to design patterns, we see that the features of Rust allow 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). TODO: Maybe include some code to illustrate the traits. diff --git a/patterns/newtype.md b/patterns/newtype.md index fbc0b246..6b023747 100644 --- a/patterns/newtype.md +++ b/patterns/newtype.md @@ -7,7 +7,8 @@ not be enough? For example, if we want to create a custom `Display` implementation for `String` due to security considerations (e.g. passwords). -For such cases we could use the `Newtype` pattern to provide __type safety__ and __encapsulation__. +For such cases we could use the `Newtype` pattern to provide __type safety__ +and __encapsulation__. ## Description @@ -88,20 +89,23 @@ most common uses, but they can be used for other reasons: - restricting functionality (reduce the functions exposed or traits implemented), - making a type with copy semantics have move semantics, -- abstraction by providing a more concrete type and thus hiding internal types, e.g., +- abstraction by providing a more concrete type and thus hiding internal types, + e.g., ```rust,ignore pub struct Foo(Bar); ``` -Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. +Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. ## See also - [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) - [Newtypes in Haskell](https://wiki.haskell.org/Newtype) - [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) -- [derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. +- [derive_more](https://crates.io/crates/derive_more), a crate for deriving many + builtin traits on newtypes. - [The Newtype Pattern In Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html) diff --git a/patterns/small-crates.md b/patterns/small-crates.md index bb9a6de0..d777ffd7 100644 --- a/patterns/small-crates.md +++ b/patterns/small-crates.md @@ -4,33 +4,42 @@ Prefer small crates that do one thing well. -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. +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. ## Advantages * Small crates are easier to understand, and encourage more modular code. * 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. -* 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. + For example, the `url` crate was developed as part of the Servo browser engine, + but has since found wide use outside the project. * 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. ## Disadvantages -* 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`. -* Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious. -* Two small crates may be less optimized than one large one, since the compiler does not perform link-time optimization (LTO) by default. +* 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`. +* Packages on crates.io are not curated. A crate may be poorly written, have + unhelpful documentation, or be outright malicious. +* Two small crates may be less optimized than one large one, since the compiler + does not perform link-time optimization (LTO) by default. ## Examples -The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions for converting `&T` to `&[T]`. +The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions +for converting `&T` to `&[T]`. -The [`url`](https://crates.io/crates/url) crate provides tools for working with URLs. +The [`url`](https://crates.io/crates/url) crate provides tools for working with +URLs. -The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a function to query the number of CPUs on a machine. +The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a function to +query the number of CPUs on a machine. ## See also diff --git a/patterns/strategy.md b/patterns/strategy.md index 9dc5d65a..e573b0ad 100644 --- a/patterns/strategy.md +++ b/patterns/strategy.md @@ -6,13 +6,14 @@ The [Strategy design pattern](https://en.wikipedia.org/wiki/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). -The basic idea behind the Strategy pattern is that, given an algorithm 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. - -In this way, a client using the algorithm may choose a specific 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. +The basic idea behind the Strategy pattern is that, given an algorithm 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. + +In this way, a client using the algorithm may choose a specific 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". ## Motivation @@ -20,15 +21,15 @@ This is why we call it "Dependency Inversion". 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 completly new format, -or just modify one of the existing 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 completly new +format, or just modify one of the existing formats. ## Example -In this example our invariants (or abstractions) are `Context`, `Formatter`, and `Report`, -while `Text` and `Json` are our strategy structs. -These strategies have to implement the `Formatter` trait. +In this example our invariants (or abstractions) are `Context`, `Formatter`, +and `Report`, while `Text` and `Json` are our strategy structs. These strategies +have to implement the `Formatter` trait. ```rust use std::collections::HashMap; @@ -93,18 +94,17 @@ fn main() { ## Advantages -The main advantage is separation of concerns. For example, in this case `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 context and a specific trait and method to implement, -i.e,`Formatter` and `run`. +The main advantage is separation of concerns. For example, in this case `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 context and a specific +trait and method to implement, i.e,`Formatter` and `run`. ## Disadvantages For each strategy there must be implemented at least one module, so number 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. +increases with number of strategies. If there are many strategies to choose from +then users have to know how strategies differ from one another. ## Discussion @@ -116,10 +116,12 @@ Ways of providing different strategies includes: - Use compiler feature flags, E.g. `json` feature, `text` feature - Separated as crates, E.g. `json` crate, `text` crate -Serde crate is a good example of the `Strategy` pattern in action. Serde 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. +Serde crate is a good example of the `Strategy` pattern in action. Serde 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. However, we don't need to use traits in order to design this pattern in Rust. diff --git a/patterns/unsafe-mods.md b/patterns/unsafe-mods.md index d5b4c5e8..d746687f 100644 --- a/patterns/unsafe-mods.md +++ b/patterns/unsafe-mods.md @@ -2,15 +2,17 @@ ## Description -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. +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 ergonomi +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. ## Advantages * This restricts the unsafe code that must be audited -* Writing the outer module is much easier, since you can count on the guarantees of the inner module +* Writing the outer module is much easier, since you can count on the guarantees +of the inner module ## Disadvantages @@ -19,10 +21,12 @@ Users may use this to gain speed benefits. ## Examples -* The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations in submodules, presenting a safe interface to users. -* `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. +* The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations + in submodules, presenting a safe interface to users. * `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. ## See also diff --git a/refactoring/index.md b/refactoring/index.md index 6b539a55..178a53b0 100644 --- a/refactoring/index.md +++ b/refactoring/index.md @@ -1,15 +1,17 @@ # Refactoring Refactoring is very important in relation to these topics. -Just as important as the other topics covered here, is how to take good code and turn it into great code. +Just as important as the other topics covered here, is how to take good code and +turn it into great code. -We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize abstractions. -We must avoid [anti-patterns](../anti_patterns/index.md) while we do this. -While they may be tempting to employ, their costs outweigh their benefits. +We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize +abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we +do this. While they may be tempting to employ, their costs outweigh their benefits. > Shortcuts make for long days. -We can also use [idioms](../idioms/index.md) to structure our code in a way that is understandable. +We can also use [idioms](../idioms/index.md) to structure our code in a way that +is understandable. ## Tests From e6d15767695b0b9a640fa426d266d24784b06a21 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 25 Jan 2021 20:06:40 +0100 Subject: [PATCH 098/217] Remove lints that have been removed (#213) Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- anti_patterns/deny-warnings.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index 7e4abf5b..91b9a0e5 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -56,28 +56,20 @@ Travis, but remember that this may break the build when something changes) without requiring a change to the code. 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: +Here is a list of warning lints that is (hopefully) safe to deny (as of Rustc 1.48.0): ```rust,ignore #[deny(bad-style, const-err, dead-code, - extra-requirement-in-impl, improper-ctypes, - legacy-directory-ownership, non-shorthand-field-patterns, no-mangle-generic-items, overflowing-literals, path-statements , patterns-in-fns-without-body, - plugin-as-library, private-in-public, - private-no-mangle-fns, - private-no-mangle-statics, - raw-pointer-derive, - safe-extern-statics, unconditional-recursion, - unions-with-drop-fields, unused, unused-allocation, unused-comparisons, From 84bf81a47f09119e1109bdacfbaaf554a65aa579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 26 Jan 2021 20:21:52 +0100 Subject: [PATCH 099/217] Add delegation crates to See Also in Deref anti-pattern (#215) --- anti_patterns/deref.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index e081a805..3c5d8a7f 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -123,6 +123,7 @@ conversion between arbitrary types. ## See also -[Collections are smart pointers idiom](../idioms/deref.md). - -[Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/trait.Deref.html). +- [Collections are smart pointers idiom](../idioms/deref.md). +- Delegation crates for less boilerplate like [delegate](https://crates.io/crates/delegate) + or [ambassador](https://crates.io/crates/ambassador) +- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/trait.Deref.html). From 1d173dab4e95e830bfa59d53c00dc0aaa1262633 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 2 Feb 2021 20:56:01 +0100 Subject: [PATCH 100/217] Add link to a list of all clippy lints (#216) --- anti_patterns/deny-warnings.md | 1 + 1 file changed, 1 insertion(+) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index 91b9a0e5..c4efd726 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -97,6 +97,7 @@ certain that there will be more deprecated APIs in the future. ## See also +- [A collection of all clippy lints](https://rust-lang.github.io/rust-clippy/master) - [deprecate attribute] documentation - Type `rustc -W help` for a list of lints on your system. Also type `rustc --help` for a general list of options From a524dc27ea5c95544a50fabde8edeb1169848b6c Mon Sep 17 00:00:00 2001 From: Bayram Date: Fri, 5 Feb 2021 13:22:50 +0400 Subject: [PATCH 101/217] Adding Interpreter design pattern (#211) --- SUMMARY.md | 1 + patterns/interpreter.md | 147 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 patterns/interpreter.md diff --git a/SUMMARY.md b/SUMMARY.md index 9128dba8..9928c74b 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -28,6 +28,7 @@ - [Object-Based APIs](./patterns/ffi-export.md) - [Type Consolidation into Wrappers](./patterns/ffi-wrappers.md) - [Fold](./patterns/fold.md) + - [Interpreter](./patterns/interpreter.md) - [Newtype](./patterns/newtype.md) - [RAII Guards](./patterns/RAII.md) - [Prefer Small Crates](./patterns/small-crates.md) diff --git a/patterns/interpreter.md b/patterns/interpreter.md new file mode 100644 index 00000000..5f97558e --- /dev/null +++ b/patterns/interpreter.md @@ -0,0 +1,147 @@ +# Interpreter + +## Description + +If a problem occurs very often and requires long and repetitive steps to 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. + +Basically, for any kind of problems we define: + +- a [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language), +- a grammar for this language, +- an interpreter that solves the problem instances. + +## Motivation + +Our goal is to translate simple mathematical expressions into postfix 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 +`. + +## Context Free Grammar for our problem + +Our task is translate infix expressions into postfix ones. Let's define a context +free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-`, +where: + +- terminal symbols: `0`, ..., `9`, `+`, `-` +- non-terminal symbols: `exp`, `term` +- start symbol is `exp` +- and the following are production rules + +```ignore +exp -> exp + term +exp -> exp - term +exp -> term +term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 +``` + +__NOTE:__ This grammar should be further transformed depending on what we 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). + +## Solution + +We simply implement a recursive descent parser. For simplicity's sake, the code +panics when an expression is syntactically wrong (for example `2-34` or `2+5-` +are wrong according to the grammar definition). + +```rust +pub struct Interpreter<'a> { + it: std::str::Chars<'a>, +} + +impl<'a> Interpreter<'a> { + + pub fn new(infix: &'a str) -> Self { + Self { it: infix.chars() } + } + + fn next_char(&mut self) -> Option { + self.it.next() + } + + pub fn interpret(&mut self, out: &mut String) { + self.term(out); + + while let Some(op) = self.next_char() { + if op == '+' || op == '-' { + self.term(out); + out.push(op); + } else { + panic!("Unexpected symbol '{}'", op); + } + } + } + + fn term(&mut self, out: &mut String) { + match self.next_char() { + Some(ch) if ch.is_digit(10) => out.push(ch), + Some(ch) => panic!("Unexpected symbol '{}'", ch), + None => panic!("Unexpected end of string"), + } + } +} + +pub fn main() { + let mut intr = Interpreter::new("2+3"); + let mut postfix = String::new(); + intr.interpret(&mut postfix); + assert_eq!(postfix, "23+"); + + intr = Interpreter::new("1-2+3-4"); + postfix.clear(); + intr.interpret(&mut postfix); + assert_eq!(postfix, "12-3+4-"); +} +``` + +## Discussion + +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 to define special syntax and rules +on how to expand this syntax into source code. + +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. + +```rust +macro_rules! norm { + ($($element:expr),*) => { + { + let mut n = 0.0; + $( + n += ($element as f64)*($element as f64); + )* + n.sqrt() + } + }; +} + +fn main() { + let x = -3f64; + let y = 4f64; + + assert_eq!(3f64, norm!(x)); + assert_eq!(5f64, norm!(x, y)); + assert_eq!(0f64, norm!(0, 0, 0)); + assert_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5)); +} +``` + +## See also + +- [Interpreter pattern](https://en.wikipedia.org/wiki/Interpreter_pattern) +- [Context free grammar](https://en.wikipedia.org/wiki/Context-free_grammar) +- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html) From 4d78ffd3c3c1d323c9e94e4c98e5fca091971456 Mon Sep 17 00:00:00 2001 From: follower Date: Thu, 11 Feb 2021 00:06:10 +1300 Subject: [PATCH 102/217] Typo: Fix missing space between words. (#217) --- idioms/ffi-passing-strings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/ffi-passing-strings.md b/idioms/ffi-passing-strings.md index e7457726..18de5c83 100644 --- a/idioms/ffi-passing-strings.md +++ b/idioms/ffi-passing-strings.md @@ -42,7 +42,7 @@ pub mod unsafe_module { unsafe { // SAFETY: calling an FFI whose documentation says the pointer is - // const, so no modificationshould occur + // const, so no modification should occur seterr(c_err.as_ptr()); } From dd265b1ec106c308ccc670e8896fdfb17bfb48fb Mon Sep 17 00:00:00 2001 From: shorii Date: Sun, 21 Feb 2021 15:29:54 +0900 Subject: [PATCH 103/217] Fix typo ('indrection' to 'indirection') (#218) --- idioms/coercion-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index 89e29f8b..3498e08e 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -14,7 +14,7 @@ Such as `&str` over `&String`, `&[T]` over `&Vec`, or `&T` over `&Box`. 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 `String` has a layer of indirection, so a `&String` will have two layers of -indrection. We can avoid this by using `&str` instead, and letting `&String` +indirection. We can avoid this by using `&str` instead, and letting `&String` coerce to a `&str` whenever the function is invoked. ## Example From 96fa89b923063170eb229a4805ae67e47651b8d6 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Thu, 25 Feb 2021 05:49:30 +0800 Subject: [PATCH 104/217] Revise the FFI chapters (#190) Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- idioms/ffi-accepting-strings.md | 54 ++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/idioms/ffi-accepting-strings.md b/idioms/ffi-accepting-strings.md index 98f364d4..c4b88e60 100644 --- a/idioms/ffi-accepting-strings.md +++ b/idioms/ffi-accepting-strings.md @@ -6,17 +6,25 @@ When accepting strings via FFI through pointers, there are two principles that should be followed: 1. Keep foreign strings "borrowed", rather than copying them directly. -2. Minimize `unsafe` code during the conversion. +2. Minimize the amount of complexity and `unsafe` code involved in converting + from a C-style string to native Rust strings. ## Motivation -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 -are being accepted from a foreign caller of a Rust function. +The strings used in C have different behaviours to those used in Rust, namely: -The best practice is simple: use `CStr` in such a way as to minimize unsafe -code, and create a borrowed slice. If an owned String is needed, call -`to_string()` on the string slice. +- C strings are null-terminated while Rust strings store their length +- C strings can contain any arbitrary non-zero byte while Rust strings must be + UTF-8 +- C strings are accessed and manipulated using `unsafe` pointer operations + while interactions with Rust strings go through safe methods + +The Rust standard library comes with C equivalents of Rust's `String` and `&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. + +The `&CStr` type also allows us to work with borrowed data, meaning passing +strings between Rust and C is a zero-cost operation. ## Code Example @@ -25,20 +33,30 @@ pub mod unsafe_module { // other module content + /// Log a message at the specified level. + /// + /// # Safety + /// + /// It is the caller's guarantee to ensure `msg`: + /// + /// - is not a null pointer + /// - points to valid, initialized data + /// - points to memory ending in a null byte + /// - won't be mutated for the duration of this function call #[no_mangle] - pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) { + pub unsafe extern "C" fn mylib_log( + msg: *const libc::c_char, + level: libc::c_int + ) { let level: crate::LogLevel = match level { /* ... */ }; - let msg_str: &str = unsafe { - // SAFETY: accessing raw pointers expected to live for the call, - // and creating a shared reference that does not outlive the current - // stack frame. - match std::ffi::CStr::from_ptr(msg).to_str() { - Ok(s) => s, - Err(e) => { - crate::log_error("FFI string conversion failed"); - return; - } + // SAFETY: The caller has already guaranteed this is okay (see the + // `# Safety` section of the doc-comment). + let msg_str: &str = match std::ffi::CStr::from_ptr(msg).to_str() { + Ok(s) => s, + Err(e) => { + crate::log_error("FFI string conversion failed"); + return; } }; From e3ed5133461a3acd26e4ee44a0cdff9a494166e8 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 26 Feb 2021 02:43:04 +0800 Subject: [PATCH 105/217] Improve strategy pattern example (#241) Reduce unnecessary String creation --- patterns/strategy.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/patterns/strategy.md b/patterns/strategy.md index e573b0ad..e00d2c92 100644 --- a/patterns/strategy.md +++ b/patterns/strategy.md @@ -33,15 +33,17 @@ have to implement the `Formatter` trait. ```rust use std::collections::HashMap; + type Data = HashMap; trait Formatter { - fn format(&self, data: &Data, s: &mut String); + fn format(&self, data: &Data, buf: &mut String); } struct Report; impl Report { + // Write should be used but we kept it as String to ignore error handling fn generate(g: T, s: &mut String) { // backend operations... let mut data = HashMap::new(); @@ -54,29 +56,25 @@ impl Report { struct Text; impl Formatter for Text { - fn format(&self, data: &Data, s: &mut String) { - *s = data - .iter() - .map(|(key, val)| format!("{} {}\n", key, val)) - .collect(); + fn format(&self, data: &Data, buf: &mut String) { + for (k, v) in data { + let entry = format!("{} {}\n", k, v); + buf.push_str(&entry); + } } } struct Json; impl Formatter for Json { - fn format(&self, data: &Data, s: &mut String) { - *s = String::from("["); - let mut iter = data.into_iter(); - if let Some((key, val)) = iter.next() { - let entry = format!(r#"{{"{}":"{}"}}"#, key, val); - s.push_str(&entry); - while let Some((key, val)) = iter.next() { - s.push(','); - let entry = format!(r#"{{"{}":"{}"}}"#, key, val); - s.push_str(&entry); - } + fn format(&self, data: &Data, buf: &mut String) { + buf.push('['); + for (k, v) in data.into_iter() { + let entry = format!(r#"{{"{}":"{}"}}"#, k, v); + buf.push_str(&entry); + buf.push(','); } - s.push(']'); + buf.pop(); // remove extra , at the end + buf.push(']'); } } @@ -86,6 +84,7 @@ fn main() { assert!(s.contains("one 1")); assert!(s.contains("two 2")); + s.clear(); // reuse the same buffer Report::generate(Json, &mut s); assert!(s.contains(r#"{"one":"1"}"#)); assert!(s.contains(r#"{"two":"2"}"#)); From 606bcffa4439f51d9ef1f2b8f166698290871165 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Thu, 25 Feb 2021 20:56:37 +0100 Subject: [PATCH 106/217] Structural changes to patterns subfolder (#219) --- SUMMARY.md | 38 ++++++++++--------- .../accepting-strings.md} | 0 idioms/{ffi-errors.md => ffi/errors.md} | 0 idioms/{ffi-intro.md => ffi/intro.md} | 6 +-- .../passing-strings.md} | 0 patterns/{ => behavioural}/RAII.md | 0 patterns/{ => behavioural}/interpreter.md | 0 patterns/behavioural/intro.md | 6 +++ patterns/{ => behavioural}/newtype.md | 0 patterns/{ => behavioural}/strategy.md | 0 patterns/{ => behavioural}/visitor.md | 0 patterns/{ => creational}/builder.md | 0 patterns/{ => creational}/fold.md | 0 patterns/creational/intro.md | 8 ++++ patterns/entry.md | 35 ----------------- patterns/{ffi-export.md => ffi/export.md} | 8 ++-- patterns/{ffi-intro.md => ffi/intro.md} | 4 +- patterns/{ffi-wrappers.md => ffi/wrappers.md} | 2 +- patterns/late-bounds.md | 35 ----------------- patterns/{ => structural}/compose-structs.md | 0 patterns/structural/intro.md | 6 +++ patterns/{ => structural}/small-crates.md | 0 patterns/{ => structural}/unsafe-mods.md | 0 23 files changed, 50 insertions(+), 98 deletions(-) rename idioms/{ffi-accepting-strings.md => ffi/accepting-strings.md} (100%) rename idioms/{ffi-errors.md => ffi/errors.md} (100%) rename idioms/{ffi-intro.md => ffi/intro.md} (58%) rename idioms/{ffi-passing-strings.md => ffi/passing-strings.md} (100%) rename patterns/{ => behavioural}/RAII.md (100%) rename patterns/{ => behavioural}/interpreter.md (100%) create mode 100644 patterns/behavioural/intro.md rename patterns/{ => behavioural}/newtype.md (100%) rename patterns/{ => behavioural}/strategy.md (100%) rename patterns/{ => behavioural}/visitor.md (100%) rename patterns/{ => creational}/builder.md (100%) rename patterns/{ => creational}/fold.md (100%) create mode 100644 patterns/creational/intro.md delete mode 100644 patterns/entry.md rename patterns/{ffi-export.md => ffi/export.md} (97%) rename patterns/{ffi-intro.md => ffi/intro.md} (66%) rename patterns/{ffi-wrappers.md => ffi/wrappers.md} (98%) delete mode 100644 patterns/late-bounds.md rename patterns/{ => structural}/compose-structs.md (100%) create mode 100644 patterns/structural/intro.md rename patterns/{ => structural}/small-crates.md (100%) rename patterns/{ => structural}/unsafe-mods.md (100%) diff --git a/SUMMARY.md b/SUMMARY.md index 9928c74b..696c5cac 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -10,10 +10,10 @@ - [Finalisation in Destructors](./idioms/dtor-finally.md) - [`mem::{take(_), replace(_)}`](./idioms/mem-replace.md) - [On-Stack Dynamic Dispatch](./idioms/on-stack-dyn-dispatch.md) - - [Foreign function interface usage](./idioms/ffi-intro.md) - - [Idiomatic Errors](./idioms/ffi-errors.md) - - [Accepting Strings](./idioms/ffi-accepting-strings.md) - - [Passing Strings](./idioms/ffi-passing-strings.md) + - [Foreign function interface (FFI)](./idioms/ffi/intro.md) + - [Idiomatic Errors](./idioms/ffi/errors.md) + - [Accepting Strings](./idioms/ffi/accepting-strings.md) + - [Passing Strings](./idioms/ffi/passing-strings.md) - [Iterating over an `Option`](./idioms/option-iter.md) - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) - [Privacy For Extensibility](./idioms/priv-extend.md) @@ -21,20 +21,22 @@ - [Temporary mutability](./idioms/temporary-mutability.md) - [Design Patterns](./patterns/index.md) - - [Builder](./patterns/builder.md) - - [Compose Structs](./patterns/compose-structs.md) - - [Entry API](./patterns/entry.md) - - [Foreign function interface usage](./patterns/ffi-intro.md) - - [Object-Based APIs](./patterns/ffi-export.md) - - [Type Consolidation into Wrappers](./patterns/ffi-wrappers.md) - - [Fold](./patterns/fold.md) - - [Interpreter](./patterns/interpreter.md) - - [Newtype](./patterns/newtype.md) - - [RAII Guards](./patterns/RAII.md) - - [Prefer Small Crates](./patterns/small-crates.md) - - [Strategy](./patterns/strategy.md) - - [Contain unsafety in small modules](./patterns/unsafe-mods.md) - - [Visitor](./patterns/visitor.md) + - [Behavioural](./patterns/behavioural/intro.md) + - [Interpreter](./patterns/behavioural/interpreter.md) + - [Newtype](./patterns/behavioural/newtype.md) + - [RAII Guards](./patterns/behavioural/RAII.md) + - [Strategy](./patterns/behavioural/strategy.md) + - [Visitor](./patterns/behavioural/visitor.md) + - [Creational](./patterns/creational/intro.md) + - [Builder](./patterns/creational/builder.md) + - [Fold](./patterns/creational/fold.md) + - [Structural](./patterns/structural/intro.md) + - [Compose Structs](./patterns/structural/compose-structs.md) + - [Prefer Small Crates](./patterns/structural/small-crates.md) + - [Contain unsafety in small modules](./patterns/structural/unsafe-mods.md) + - [Foreign function interface (FFI)](./patterns/ffi/intro.md) + - [Object-Based APIs](./patterns/ffi/export.md) + - [Type Consolidation into Wrappers](./patterns/ffi/wrappers.md) - [Anti-patterns](./anti_patterns/index.md) - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) diff --git a/idioms/ffi-accepting-strings.md b/idioms/ffi/accepting-strings.md similarity index 100% rename from idioms/ffi-accepting-strings.md rename to idioms/ffi/accepting-strings.md diff --git a/idioms/ffi-errors.md b/idioms/ffi/errors.md similarity index 100% rename from idioms/ffi-errors.md rename to idioms/ffi/errors.md diff --git a/idioms/ffi-intro.md b/idioms/ffi/intro.md similarity index 58% rename from idioms/ffi-intro.md rename to idioms/ffi/intro.md index 26fc542a..d1f14971 100644 --- a/idioms/ffi-intro.md +++ b/idioms/ffi/intro.md @@ -6,9 +6,9 @@ traps for inexperienced users of `unsafe` Rust. This section contains idioms that may be useful when doing FFI. -1. [Idiomatic Errors](./ffi-errors.md) - Error handling with integer codes and +1. [Idiomatic Errors](./errors.md) - Error handling with integer codes and sentinel return values (such as `NULL` pointers) -2. [Accepting Strings](./ffi-accepting-strings.md) with minimal unsafe code +2. [Accepting Strings](./accepting-strings.md) with minimal unsafe code -3. [Passing Strings](./ffi-passing-strings.md) to FFI functions +3. [Passing Strings](./passing-strings.md) to FFI functions diff --git a/idioms/ffi-passing-strings.md b/idioms/ffi/passing-strings.md similarity index 100% rename from idioms/ffi-passing-strings.md rename to idioms/ffi/passing-strings.md diff --git a/patterns/RAII.md b/patterns/behavioural/RAII.md similarity index 100% rename from patterns/RAII.md rename to patterns/behavioural/RAII.md diff --git a/patterns/interpreter.md b/patterns/behavioural/interpreter.md similarity index 100% rename from patterns/interpreter.md rename to patterns/behavioural/interpreter.md diff --git a/patterns/behavioural/intro.md b/patterns/behavioural/intro.md new file mode 100644 index 00000000..8ca43a04 --- /dev/null +++ b/patterns/behavioural/intro.md @@ -0,0 +1,6 @@ +# Behavioural Patterns + +From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern): + +> Design patterns that identify common communication patterns among objects. +> By doing so, these patterns increase flexibility in carrying out communication. diff --git a/patterns/newtype.md b/patterns/behavioural/newtype.md similarity index 100% rename from patterns/newtype.md rename to patterns/behavioural/newtype.md diff --git a/patterns/strategy.md b/patterns/behavioural/strategy.md similarity index 100% rename from patterns/strategy.md rename to patterns/behavioural/strategy.md diff --git a/patterns/visitor.md b/patterns/behavioural/visitor.md similarity index 100% rename from patterns/visitor.md rename to patterns/behavioural/visitor.md diff --git a/patterns/builder.md b/patterns/creational/builder.md similarity index 100% rename from patterns/builder.md rename to patterns/creational/builder.md diff --git a/patterns/fold.md b/patterns/creational/fold.md similarity index 100% rename from patterns/fold.md rename to patterns/creational/fold.md diff --git a/patterns/creational/intro.md b/patterns/creational/intro.md new file mode 100644 index 00000000..782fdc80 --- /dev/null +++ b/patterns/creational/intro.md @@ -0,0 +1,8 @@ +# Creational Patterns + +From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern): + +> 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. diff --git a/patterns/entry.md b/patterns/entry.md deleted file mode 100644 index b06a07e5..00000000 --- a/patterns/entry.md +++ /dev/null @@ -1,35 +0,0 @@ -# Entry API - -## Description - -A short, prose description of the pattern. - -## Example - -```rust -// An example of the pattern in action, should be mostly code, commented -// liberally. -``` - -## Motivation - -Why and where you should use the pattern - -## Advantages - -Good things about this pattern. - -## Disadvantages - -Bad things about this pattern. Possible contraindications. - -## Discussion - -TODO vs insert_or_update etc. - -## See also - -[RFC](https://github.com/rust-lang/rfcs/blob/master/text/0216-collection-views.md) -[RFC](https://github.com/rust-lang/rfcs/blob/8e2d3a3341da533f846f61f10335b72c9a9f4740/text/0921-entry_v3.md) - -[Hashmap::entry docs](https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry) diff --git a/patterns/ffi-export.md b/patterns/ffi/export.md similarity index 97% rename from patterns/ffi-export.md rename to patterns/ffi/export.md index 6bb719e5..67f93826 100644 --- a/patterns/ffi-export.md +++ b/patterns/ffi/export.md @@ -246,15 +246,15 @@ Second, depending on the relationships of the API's parts, significant design ef may be involved. Many of the easier design points have other patterns associated with them: -- [Wrapper Type Consolidation](./ffi-wrappers.md) groups multiple Rust types together +- [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types together into an opaque "object" -- [FFI Error Passing](../idioms/ffi-errors.md) explains error handling with integer +- [FFI Error Passing](../idioms/ffi/errors.md) explains error handling with integer codes and sentinel return values (such as `NULL` pointers) -- [Accepting Foreign Strings](../idioms/ffi-accepting-strings.md) allows accepting +- [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) + [Passing Strings to FFI](../idioms/ffi/passing-strings.md) 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. diff --git a/patterns/ffi-intro.md b/patterns/ffi/intro.md similarity index 66% rename from patterns/ffi-intro.md rename to patterns/ffi/intro.md index b2df4bdf..f65a0d28 100644 --- a/patterns/ffi-intro.md +++ b/patterns/ffi/intro.md @@ -6,8 +6,8 @@ for inexperienced users of unsafe Rust. This section contains design patterns that may be useful when doing FFI. -1. [Object-Based API](./ffi-export.md) design that has good memory safety characteristics, +1. [Object-Based API](./export.md) design that has good memory safety characteristics, and a clean boundary of what is safe and what is unsafe -2. [Type Consolidation into Wrappers](./ffi-wrappers.md) - group multiple Rust types +2. [Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust types together into an opaque "object" diff --git a/patterns/ffi-wrappers.md b/patterns/ffi/wrappers.md similarity index 98% rename from patterns/ffi-wrappers.md rename to patterns/ffi/wrappers.md index 7adcf881..77312596 100644 --- a/patterns/ffi-wrappers.md +++ b/patterns/ffi/wrappers.md @@ -63,7 +63,7 @@ As a result, the wrapper is simple and contains no `unsafe` code. ## Advantages This makes APIs safer to use, avoiding issues with lifetimes between types. -See [Object-Based APIs](./ffi-export.md) for more on the advantages and pitfalls +See [Object-Based APIs](./export.md) for more on the advantages and pitfalls this avoids. ## Disadvantages diff --git a/patterns/late-bounds.md b/patterns/late-bounds.md deleted file mode 100644 index fe5ebe79..00000000 --- a/patterns/late-bounds.md +++ /dev/null @@ -1,35 +0,0 @@ -# Late bound bounds - -## Description - -TODO late binding of bounds for better APIs (i.e., Mutex's don't require Send) - -## Example - -```rust -// An example of the pattern in action, should be mostly code, commented -// liberally. -``` - -## Motivation - -Why and where you should use the pattern - -## Advantages - -Good things about this pattern. - -## Disadvantages - -Bad things about this pattern. Possible contraindications. - -## Discussion - -A deeper discussion about this pattern. You might want to cover how this is done -in other languages, alternative approaches, why this is particularly nice in -Rust, etc. - -## See also - -Related patterns (link to the pattern file). Versions of this pattern in other -languages. diff --git a/patterns/compose-structs.md b/patterns/structural/compose-structs.md similarity index 100% rename from patterns/compose-structs.md rename to patterns/structural/compose-structs.md diff --git a/patterns/structural/intro.md b/patterns/structural/intro.md new file mode 100644 index 00000000..34d9cc9b --- /dev/null +++ b/patterns/structural/intro.md @@ -0,0 +1,6 @@ +# Structural Patterns + +From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern): + +> Design patterns that ease the design by identifying a simple way to realize relationships +> among entities. diff --git a/patterns/small-crates.md b/patterns/structural/small-crates.md similarity index 100% rename from patterns/small-crates.md rename to patterns/structural/small-crates.md diff --git a/patterns/unsafe-mods.md b/patterns/structural/unsafe-mods.md similarity index 100% rename from patterns/unsafe-mods.md rename to patterns/structural/unsafe-mods.md From 249a154e818a6a60949f25844c585ca939b1c460 Mon Sep 17 00:00:00 2001 From: Gianluca Recchia Date: Sun, 28 Feb 2021 23:46:55 +0100 Subject: [PATCH 107/217] Improve wording and fix typo (#242) --- idioms/rustdoc-init.md | 4 ++-- patterns/structural/unsafe-mods.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 63f7d1a2..96df84e8 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -80,9 +80,9 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages -As example is in a function, the code will not be tested. Though it still will +As example is in a function, the code will not be tested. Though it will still be checked to make sure it compiles when running a `cargo test`. So this pattern is -most useful when need `no_run`. With this, you do not need to add `no_run`. +most useful when you need `no_run`. With this, you do not need to add `no_run`. ## Discussion diff --git a/patterns/structural/unsafe-mods.md b/patterns/structural/unsafe-mods.md index d746687f..682bd631 100644 --- a/patterns/structural/unsafe-mods.md +++ b/patterns/structural/unsafe-mods.md @@ -4,7 +4,7 @@ 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 ergonomi +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. From 077e247109607facdd5ce22554ec3657889fdaa8 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 2 Mar 2021 22:11:50 +0100 Subject: [PATCH 108/217] Updating mdbook version (#243) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 5cbca006..2a8a1d7c 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.6 +MDBOOK_VERSION=0.4.7 From 881f51fef1084d9d4c6813a22b304b16db65a55b Mon Sep 17 00:00:00 2001 From: Darius Wiles Date: Mon, 8 Mar 2021 07:06:44 -0800 Subject: [PATCH 109/217] Fix format by moving advantage to new bullet (#245) --- patterns/structural/small-crates.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/patterns/structural/small-crates.md b/patterns/structural/small-crates.md index d777ffd7..01060e31 100644 --- a/patterns/structural/small-crates.md +++ b/patterns/structural/small-crates.md @@ -14,7 +14,8 @@ We should take advantage of this tooling, and use smaller, more fine-grained dep * Small crates are easier to understand, and encourage more modular code. * 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. * Since the compilation unit + but has since found wide use outside the project. +* 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. From fb57f21ec115953dce7a5ad6b358feed394a470f Mon Sep 17 00:00:00 2001 From: Jaxel Rojas Date: Wed, 10 Mar 2021 08:40:13 -0400 Subject: [PATCH 110/217] Fix syntax error on code snippet (#246) * Fix syntax error on code snippet * Added comma to struct definition on code snippet * cargo fmt, remove ignore flag Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- anti_patterns/deref.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index 3c5d8a7f..c6c65426 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -25,7 +25,7 @@ public static void main(String[] args) { We can use the deref polymorphism anti-pattern to do so: -```rust,ignore +```rust use std::ops::Deref; struct Foo {} @@ -34,11 +34,10 @@ impl Foo { fn m(&self) { //.. } - } struct Bar { - f: Foo + f: Foo, } impl Deref for Bar { @@ -49,7 +48,7 @@ impl Deref for Bar { } fn main() { - let b = Bar { Foo {} }; + let b = Bar { f: Foo {} }; b.m(); } ``` From a22d81d751239dec562c0a59d620bba0572f4679 Mon Sep 17 00:00:00 2001 From: bemyak Date: Mon, 29 Mar 2021 15:14:20 +0300 Subject: [PATCH 111/217] Add builder method to struct in builder pattern (#251) --- patterns/creational/builder.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/patterns/creational/builder.md b/patterns/creational/builder.md index ab6a4981..8b3e494e 100644 --- a/patterns/creational/builder.md +++ b/patterns/creational/builder.md @@ -13,6 +13,14 @@ pub struct Foo { bar: String, } +impl Foo { + // This method will help users to discover the builder + pub fn builder() -> FooBuilder { + FooBuilder::default() + } +} + +#[derive(Default)] pub struct FooBuilder { // Probably lots of optional fields. bar: String, @@ -103,6 +111,6 @@ as well as the `FooBuilder::new().a().b().build()` style. - [Description in the style guide](https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html) - [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically implementing this pattern while avoiding the boilerplate. -- [Constructor pattern](../idioms/ctor.md) for when construction is simpler. +- [Constructor pattern](../../idioms/ctor.md) for when construction is simpler. - [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) - [Construction of complex values](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) From c9c5f700240cea64901e540cdcd87df1171b07ff Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Mon, 29 Mar 2021 23:51:47 +0200 Subject: [PATCH 112/217] Adding 'clone to satisfy the borrow checker' anti-pattern (#110) --- SUMMARY.md | 1 + anti_patterns/borrow_clone.md | 73 +++++++++++++++++++++++++++++++++++ idioms/mem-replace.md | 6 +-- 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 anti_patterns/borrow_clone.md diff --git a/SUMMARY.md b/SUMMARY.md index 696c5cac..488ec66c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -39,6 +39,7 @@ - [Type Consolidation into Wrappers](./patterns/ffi/wrappers.md) - [Anti-patterns](./anti_patterns/index.md) + - [Clone to satisfy the borrow checker](./anti_patterns/borrow_clone.md) - [`#[deny(warnings)]`](./anti_patterns/deny-warnings.md) - [Deref Polymorphism](./anti_patterns/deref.md) diff --git a/anti_patterns/borrow_clone.md b/anti_patterns/borrow_clone.md new file mode 100644 index 00000000..4ee96789 --- /dev/null +++ b/anti_patterns/borrow_clone.md @@ -0,0 +1,73 @@ +# Clone to satisfy the borrow checker + +## Description + +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. + +## Example + +```rust +// define any variable +let mut x = 5; + +// Borrow `x` -- but clone it first +let y = &mut (x.clone()); + +// perform some action on the borrow to prevent rust from optimizing this +//out of existence +*y += 1; + +// without the x.clone() two lines prior, this line would fail on compile as +// x has been borrowed +// thanks to x.clone(), x was never borrowed, and this line will run. +println!("{}", x); +``` + +## Motivation + +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. + +There are special cases -- `Rc` is designed to handle clones intelligently. +It internally manages exactly one copy of the data, and cloning it will only +clone the reference. + +There is also `Arc` which provides shared ownership of a value of type T +that is allocated in the heap. Invoking `.clone()` on `Arc` produces a new `Arc` +instance, which points to the same allocation on the heap as the source `Arc`, +while increasing a reference count. + +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. + +Even though `.clone()` is an indication of a bad pattern, sometimes +**it is fine to write inefficient code**, in cases such as when: + +- the developer is still new to ownership +- the code doesn't have great speed or memory constraints + (like hackathon projects or prototypes) +- satisfying the borrow checker is really complicated and you prefer to + optimize readability over performance + +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. + +Also be sure to always run `cargo clippy` in your project, which will detect some +cases in which `.clone()` is not necessary, like [1](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone), +[2](https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy), +[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). + +## See also + +- [`mem::{take(_), replace(_)}` to keep owned values in changed enums](../idioms/mem-replace.md) +- [`Rc` documentation, which handles .clone() intelligently](http://doc.rust-lang.org/std/rc/) +- [`Arc` documentation, a thread-safe reference-counting pointer](https://doc.rust-lang.org/std/sync/struct.Arc.html) +- [Tricks with ownership in Rust](https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html) diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index 49d6891b..3649b6d4 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -116,7 +116,5 @@ like Indiana Jones, replacing the artifact with a bag of sand. ## See also -This gets rid of the [Clone to satisfy the borrow checker] antipattern in a -specific case. - -[Clone to satisfy the borrow checker](TODO: Hinges on PR #23) +This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md) +antipattern in a specific case. From fabafb1f151dc28d0f1b0fc22213d1fff73f7958 Mon Sep 17 00:00:00 2001 From: Bayram Date: Wed, 31 Mar 2021 00:49:24 +0400 Subject: [PATCH 113/217] Adding Command pattern (#247) --- SUMMARY.md | 1 + patterns/behavioural/command.md | 222 ++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 patterns/behavioural/command.md diff --git a/SUMMARY.md b/SUMMARY.md index 488ec66c..41191739 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -22,6 +22,7 @@ - [Design Patterns](./patterns/index.md) - [Behavioural](./patterns/behavioural/intro.md) + - [Command](./patterns/behavioural/command.md) - [Interpreter](./patterns/behavioural/interpreter.md) - [Newtype](./patterns/behavioural/newtype.md) - [RAII Guards](./patterns/behavioural/RAII.md) diff --git a/patterns/behavioural/command.md b/patterns/behavioural/command.md new file mode 100644 index 00000000..c878963a --- /dev/null +++ b/patterns/behavioural/command.md @@ -0,0 +1,222 @@ +# Command + +## Description + +The basic idea of the Command pattern is to separate out actions into its own +objects and pass them as parameters. + +## Motivation + +Suppose we have a sequence of actions or transactions encapsulated as 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. + +## Example + +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` +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. + +## Approach: Using trait objects + +We define a common trait which encapsulates our command with two operations +`execute` and `rollback`. All command `structs` must implement this trait. + +```rust +pub trait Migration { + fn execute(&self) -> &str; + fn rollback(&self) -> &str; +} + +pub struct CreateTable; +impl Migration for CreateTable { + fn execute(&self) -> &str { + "create table" + } + fn rollback(&self) -> &str { + "drop table" + } +} + +pub struct AddField; +impl Migration for AddField { + fn execute(&self) -> &str { + "add field" + } + fn rollback(&self) -> &str { + "remove field" + } +} + +struct Schema { + commands: Vec>, +} + +impl Schema { + fn new() -> Self { + Self { commands: vec![] } + } + + fn add_migration(&mut self, cmd: Box) { + self.commands.push(cmd); + } + + fn execute(&self) -> Vec<&str> { + self.commands.iter().map(|cmd| cmd.execute()).collect() + } + fn rollback(&self) -> Vec<&str> { + self.commands + .iter() + .rev() // reverse iterator's direction + .map(|cmd| cmd.rollback()) + .collect() + } +} + +fn main() { + let mut schema = Schema::new(); + + let cmd = Box::new(CreateTable); + schema.add_migration(cmd); + let cmd = Box::new(AddField); + schema.add_migration(cmd); + + assert_eq!(vec!["create table", "add field"], schema.execute()); + assert_eq!(vec!["remove field", "drop table"], schema.rollback()); +} +``` + +## Approach: Using function pointers + +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. + +```rust +type FnPtr = fn() -> String; +struct Command { + execute: FnPtr, + rollback: FnPtr, +} + +struct Schema { + commands: Vec, +} + +impl Schema { + fn new() -> Self { + Self { commands: vec![] } + } + fn add_migration(&mut self, execute: FnPtr, rollback: FnPtr) { + self.commands.push(Command { execute, rollback }); + } + fn execute(&self) -> Vec { + self.commands.iter().map(|cmd| (cmd.execute)()).collect() + } + fn rollback(&self) -> Vec { + self.commands + .iter() + .rev() + .map(|cmd| (cmd.rollback)()) + .collect() + } +} + +fn add_field() -> String { + "add field".to_string() +} + +fn remove_field() -> String { + "remove field".to_string() +} + +fn main() { + let mut schema = Schema::new(); + schema.add_migration(|| "create table".to_string(), || "drop table".to_string()); + schema.add_migration(add_field, remove_field); + assert_eq!(vec!["create table", "add field"], schema.execute()); + assert_eq!(vec!["remove field", "drop table"], schema.rollback()); +} +``` + +## Approach: Using `Fn` trait objects + +Finally, instead of defining a common command trait we could store +each command implementing the `Fn` trait separately in vectors. + +```rust +type Migration<'a> = Box &'a str>; + +struct Schema<'a> { + executes: Vec>, + rollbacks: Vec>, +} + +impl<'a> Schema<'a> { + fn new() -> Self { + Self { + executes: vec![], + rollbacks: vec![], + } + } + fn add_migration(&mut self, execute: E, rollback: R) + where + E: Fn() -> &'a str + 'static, + R: Fn() -> &'a str + 'static, + { + self.executes.push(Box::new(execute)); + self.rollbacks.push(Box::new(rollback)); + } + fn execute(&self) -> Vec<&str> { + self.executes.iter().map(|cmd| cmd()).collect() + } + fn rollback(&self) -> Vec<&str> { + self.rollbacks.iter().rev().map(|cmd| cmd()).collect() + } +} + +fn add_field() -> &'static str { + "add field" +} + +fn remove_field() -> &'static str { + "remove field" +} + +fn main() { + let mut schema = Schema::new(); + schema.add_migration(|| "create table", || "drop table"); + schema.add_migration(add_field, remove_field); + assert_eq!(vec!["create table", "add field"], schema.execute()); + assert_eq!(vec!["remove field", "drop table"], schema.rollback()); +} +``` + +## Discussion + +If our commands are small and may be defined as functions or passed as a 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 seperate 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. + +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. + +## See also + +- [Command pattern](https://en.wikipedia.org/wiki/Command_pattern) + +- [Another example for the `command` pattern](https://web.archive.org/web/20210223131236/https://chercher.tech/rust/command-design-pattern-rust) From 22de99a82ba27f539c7937ceb3704e4cb082e846 Mon Sep 17 00:00:00 2001 From: Wenxuan Date: Tue, 13 Apr 2021 19:27:42 +0800 Subject: [PATCH 114/217] Improve mem-replace examples (#253) --- idioms/mem-replace.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index 3649b6d4..5275fc1c 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -19,20 +19,13 @@ enum MyEnum { } fn a_to_b(e: &mut MyEnum) { - - // we mutably borrow `e` here. This precludes us from changing it directly - // as in `*e = ...`, because the borrow checker won't allow it. Therefore - // the assignment to `e` must be outside the `if let` clause. - *e = if let MyEnum::A { ref mut name, x: 0 } = *e { - + if let MyEnum::A { name, x: 0 } = e { // this takes out our `name` and put in an empty String instead // (note that empty strings don't allocate). // Then, construct the new enum variant (which will - // be assigned to `*e`, because it is the result of the `if let` expression). - MyEnum::B { name: mem::take(name) } - - // In all other cases, we return immediately, thus skipping the assignment - } else { return } + // be assigned to `*e`). + *e = MyEnum::B { name: mem::take(name) } + } } ``` @@ -50,11 +43,11 @@ enum MultiVariateEnum { fn swizzle(e: &mut MultiVariateEnum) { use MultiVariateEnum::*; - *e = match *e { + *e = match e { // Ownership rules do not allow taking `name` by value, but we cannot // take the value out of a mutable reference, unless we replace it: - A { ref mut name } => B { name: mem::take(name) }, - B { ref mut name } => A { name: mem::take(name) }, + A { name } => B { name: mem::take(name) }, + B { name } => A { name: mem::take(name) }, C => D, D => C } From 680509aeee7e34461b5116342d1f42135fed14fe Mon Sep 17 00:00:00 2001 From: jhwgh1968 Date: Fri, 16 Apr 2021 09:14:29 +0000 Subject: [PATCH 115/217] Add Generics as Type Classes (#249) --- SUMMARY.md | 1 + functional/generics-type-classes.md | 286 ++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 functional/generics-type-classes.md diff --git a/SUMMARY.md b/SUMMARY.md index 41191739..abce59cb 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -46,6 +46,7 @@ - [Functional Programming](./functional/index.md) - [Programming paradigms](./functional/paradigms.md) + - [Generics as Type Classes](./functional/generics-type-classes.md) - [Additional Resources](./additional_resources/index.md) - [Design principles](./additional_resources/design-principles.md) diff --git a/functional/generics-type-classes.md b/functional/generics-type-classes.md new file mode 100644 index 00000000..9999e921 --- /dev/null +++ b/functional/generics-type-classes.md @@ -0,0 +1,286 @@ +# Generics as Type Classes + +## Description + +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. + +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. + +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. + +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. + +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. + +The nearest equivalent is the runtime polymorphism in Javascript and Python, +where new members can be added to objects willy-nilly by any constructor. +Unlike those languages, however, 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. + +## Example + +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). + +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. + +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: + +```rust,ignore + +enum AuthInfo { + Nfs(crate::nfs::AuthInfo), + Bootp(crate::bootp::AuthInfo), +} + +struct FileDownloadRequest { + file_name: PathBuf, + authentication: AuthInfo, +} +``` + +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. + +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. + +Here is how getting an NFS mount point would look: + +```rust,ignore +struct FileDownloadRequest { + file_name: PathBuf, + authentication: AuthInfo, + mount_point: Option, +} + +impl FileDownloadRequest { + // ... other methods ... + + /// Gets an NFS mount point if this is an NFS request. Otherwise, + /// return None. + pub fn mount_point(&self) -> Option<&Path> { + self.mount_point.as_ref() + } +} +``` + +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! + +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. + +In Rust, this is actually possible! The solution is to *add a generic type* in +order to split the API. + +Here is what that looks like: + +```rust +use std::path::{Path, PathBuf}; + +mod nfs { + #[derive(Clone)] + pub(crate) struct AuthInfo(String); // NFS session management omitted +} + +mod bootp { + pub(crate) struct AuthInfo(); // no authentication in bootp +} + +// private module, lest outside users invent their own protocol kinds! +mod proto_trait { + use std::path::{Path, PathBuf}; + use super::{bootp, nfs}; + + pub(crate) trait ProtoKind { + type AuthInfo; + fn auth_info(&self) -> Self::AuthInfo; + } + + pub struct Nfs { + auth: nfs::AuthInfo, + mount_point: PathBuf, + } + + impl Nfs { + pub(crate) fn mount_point(&self) -> &Path { + &self.mount_point + } + } + + impl ProtoKind for Nfs { + type AuthInfo = nfs::AuthInfo; + fn auth_info(&self) -> Self::AuthInfo { + self.auth.clone() + } + } + + pub struct Bootp(); // no additional metadata + + impl ProtoKind for Bootp { + type AuthInfo = bootp::AuthInfo; + fn auth_info(&self) -> Self::AuthInfo { + bootp::AuthInfo() + } + } +} + +use proto_trait::ProtoKind; // keep internal to prevent impls +pub use proto_trait::{Nfs, Bootp}; // re-export so callers can see them + +struct FileDownloadRequest { + file_name: PathBuf, + protocol: P, +} + +// all common API parts go into a generic impl block +impl FileDownloadRequest

{ + fn file_path(&self) -> &Path { + &self.file_name + } + + fn auth_info(&self) -> P::AuthInfo { + self.protocol.auth_info() + } +} + +// all protocol-specific impls go into their own block +impl FileDownloadRequest { + fn mount_point(&self) -> &Path { + self.protocol.mount_point() + } +} + +fn main() { + // your code here +} +``` + +With this approach, if the user were to make a mistake and use the wrong +type; + +```rust,ignore +fn main() { + let mut socket = crate::bootp::listen()?; + while let Some(request) = socket.next_request()? { + match request.mount_point().as_ref() + "/secure" => socket.send("Access denied"), + _ => {} // continue on... + } + // Rest of the code here + } +} +``` + +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! + +## Advantages + +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. + +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. + +Both of these mean there are fewer lines of code, and they are better organized. + +## Disadvantages + +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. + +## Alternatives + +* If a type seems to need a "split API" due to construction or partial +initialization, consider the +[Builder Pattern](../patterns/creational/builder.md) instead. + +* If the API between types does not change -- only the behavior does -- then +the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used +instead. + +## See also + +This pattern is used throughout the standard library: + +* `Vec` can be cast from a String, unlike every other type of `Vec`.[^1] +* They can also be cast into a binary heap, but only if they contain a type + that implements the `Ord` trait.[^2] +* The `to_string` method was specialized for `Cow` only of type `str`.[^3] + +It is also used by several popular crates to allow API flexibility: + +* 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] + +* 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] + +* 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 techinque. [^6] + +[^1]: See: [impl From\ for Vec\]( +https://doc.rust-lang.org/stable/src/std/ffi/c_str.rs.html#799-801) + +[^2]: See: [impl\ From\\> for BinaryHeap\]( +https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) + +[^3]: See: [impl\<'_\> ToString for Cow\<'_, str>]( +https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) + +[^4]: 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) + +[^5]: 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) + +[^6]: 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) From a1523995ec3133d36a2106b8578b994a947a15b1 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 20 Apr 2021 22:18:23 +0200 Subject: [PATCH 116/217] Fix internal links (#255) --- idioms/ctor.md | 4 ++-- idioms/dtor-finally.md | 2 +- idioms/on-stack-dyn-dispatch.md | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/idioms/ctor.md b/idioms/ctor.md index aef2aaef..d9c45131 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -32,5 +32,5 @@ impl Vec { ## See also -The [builder pattern](../patterns/builder.md) for constructing objects where -there are multiple configurations. +The [builder pattern](../patterns/creational/builder.md) for constructing objects +where there are multiple configurations. diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index 9c6b0374..cbcd8186 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -87,4 +87,4 @@ resources in an unexpected state. ## See also -[RAII](../patterns/RAII.md). +[RAII guards](../patterns/behavioural/RAII.md). diff --git a/idioms/on-stack-dyn-dispatch.md b/idioms/on-stack-dyn-dispatch.md index c0764589..d45f3ca9 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/idioms/on-stack-dyn-dispatch.md @@ -84,7 +84,8 @@ Read` ## See also * [Finalisation in destructors](dtor-finally.md) and -[RAII guards](../patterns/RAII.md) can benefit from tight control over lifetimes. +[RAII guards](../patterns/behavioural/RAII.md) can benefit from tight control over +lifetimes. * For conditionally filled `Option<&T>`s of (mutable) references, one can initialize an `Option` directly and use its [`.as_ref()`] method to get an optional reference. From b809265f549fc334e9a638223c0aeee7b214ff2b Mon Sep 17 00:00:00 2001 From: koalp <49921473+koalp@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:56:20 +0200 Subject: [PATCH 117/217] Fix internal links II (#256) --- idioms/mem-replace.md | 4 ++-- patterns/behavioural/RAII.md | 2 +- patterns/behavioural/visitor.md | 4 ++-- patterns/creational/fold.md | 8 ++++---- patterns/ffi/export.md | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index 5275fc1c..d03c9d5c 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -65,8 +65,8 @@ change the value (as in the example above). 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 into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy -the borrow checker] antipattern. Anyway, we can avoid the extra allocation by -changing `e` with only a mutable borrow. +the borrow checker](../anti_patterns/borrow_clone.md) antipattern. Anyway, we +can avoid the extra allocation by changing `e` with only a mutable borrow. `mem::take` lets us swap out the value, replacing it with it's default value, and returning the previous value. For `String`, the default value is an empty diff --git a/patterns/behavioural/RAII.md b/patterns/behavioural/RAII.md index d7b6dbfd..f27e6f02 100644 --- a/patterns/behavioural/RAII.md +++ b/patterns/behavioural/RAII.md @@ -110,7 +110,7 @@ works just as well. ## See also -[Finalisation in destructors idiom](../idioms/dtor-finally.md) +[Finalisation in destructors idiom](../../idioms/dtor-finally.md) RAII is a common pattern in C++: [cppreference.com](http://en.cppreference.com/w/cpp/language/raii), [wikipedia][wikipedia]. diff --git a/patterns/behavioural/visitor.md b/patterns/behavioural/visitor.md index 9f5de670..55873147 100644 --- a/patterns/behavioural/visitor.md +++ b/patterns/behavioural/visitor.md @@ -109,5 +109,5 @@ The visitor pattern is a common pattern in most OO languages. [Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern) -The [fold](fold.md) pattern is similar to visitor but produces a new version of -the visited data structure. +The [fold](../creational/fold.md) pattern is similar to visitor but produces +a new version of the visited data structure. diff --git a/patterns/creational/fold.md b/patterns/creational/fold.md index 5b91bf7a..8d8e0ccd 100644 --- a/patterns/creational/fold.md +++ b/patterns/creational/fold.md @@ -116,7 +116,7 @@ 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. -The [visitor](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. +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. diff --git a/patterns/ffi/export.md b/patterns/ffi/export.md index 67f93826..8b96a17e 100644 --- a/patterns/ffi/export.md +++ b/patterns/ffi/export.md @@ -249,12 +249,12 @@ with them: - [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types together into an opaque "object" -- [FFI Error Passing](../idioms/ffi/errors.md) explains error handling with integer +- [FFI Error Passing](../../idioms/ffi/errors.md) explains error handling with integer codes and sentinel return values (such as `NULL` pointers) -- [Accepting Foreign Strings](../idioms/ffi/accepting-strings.md) allows accepting +- [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) + [Passing Strings to FFI](../../idioms/ffi/passing-strings.md) 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. From ef80980ec74bbc0a189bb850036d5df4eb8c4621 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 14 May 2021 06:50:08 +0200 Subject: [PATCH 118/217] Updating mdbook version (#258) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 2a8a1d7c..a084ce2e 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.7 +MDBOOK_VERSION=0.4.8 From d30b026811c6fe7e376fcfb94a6a684a2fc37fae Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 9 Jul 2021 06:47:12 +0800 Subject: [PATCH 119/217] Note on Vec (#262) Fix #261 --- idioms/deref.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/deref.md b/idioms/deref.md index 1815301f..ef1530da 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -11,7 +11,7 @@ and borrowed views of data. use std::ops::Deref; struct Vec { - data: T, + data: RawVec, //.. } From 84c0df77b7820b238eab7135d051dd174a852582 Mon Sep 17 00:00:00 2001 From: Joel Montes de Oca <6587811+JoelMon@users.noreply.github.com> Date: Fri, 23 Jul 2021 15:17:11 -0400 Subject: [PATCH 120/217] Fix typo (#265) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76c5b8e9..8831856e 100644 --- a/README.md +++ b/README.md @@ -35,4 +35,4 @@ directory of the repository: ## License -This content of this repository is licensed under **MPL-2.0**; see [LICENSE](./LICENSE). +The content of this repository is licensed under **MPL-2.0**; see [LICENSE](./LICENSE). From c9897ab9831325c0c3fd2b0415bb724f45a3b19e Mon Sep 17 00:00:00 2001 From: Joel Montes de Oca <6587811+JoelMon@users.noreply.github.com> Date: Fri, 23 Jul 2021 17:58:58 -0400 Subject: [PATCH 121/217] Fix grammar, add missing comma (#263) --- intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intro.md b/intro.md index 84868411..da507a62 100644 --- a/intro.md +++ b/intro.md @@ -15,7 +15,7 @@ All of these solutions work together to solve a bigger problem. ## Design patterns in Rust There are many problems that share the same form. -Due to the fact that Rust is not object-oriented design patterns vary with +Due to the fact that Rust is not object-oriented, design patterns vary with respect to other object-oriented programming languages. While the details are different, since they have the same form they can be solved using the same fundamental methods: From c23e0062082bb81e0bfda4454084a70ffdab8c20 Mon Sep 17 00:00:00 2001 From: Imbolc Date: Mon, 26 Jul 2021 21:12:45 +0300 Subject: [PATCH 122/217] improve `Default` trait example (#267) --- idioms/default.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/idioms/default.md b/idioms/default.md index 4717a029..85b29f0c 100644 --- a/idioms/default.md +++ b/idioms/default.md @@ -23,7 +23,7 @@ different names, but there can only be one `Default` implementation per type. use std::{path::PathBuf, time::Duration}; // note that we can simply auto-derive Default here. -#[derive(Default, Debug)] +#[derive(Default, Debug, PartialEq)] struct MyConfiguration { // Option defaults to None output: Option, @@ -45,6 +45,13 @@ fn main() { // do something with conf here conf.check = true; println!("conf = {:#?}", conf); + + // partial initalization with default values, creates the same instance + let conf1 = MyConfiguration { + check: true, + ..Default::default() + }; + assert_eq!(conf, conf1); } ``` From 6a7088c25c1c5d982c3de257936eb0c27a561474 Mon Sep 17 00:00:00 2001 From: Imbolc Date: Tue, 27 Jul 2021 10:11:36 +0300 Subject: [PATCH 123/217] Fix typo (#266) --- idioms/coercion-arguments.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index 3498e08e..1c13aac3 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -84,8 +84,7 @@ Even ignoring this special example, you may still find that using `&str` will give you more flexibility than using a `&String`. 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 has a word that contains three -consecutive vowels. +determine if any of the words in the sentence contain three consecutive vowels. We probably should make use of the function we have already defined and simply feed in each word from the sentence. From 9834f5719b056ebf2d6cba63ea089757bab5e52c Mon Sep 17 00:00:00 2001 From: poly000 <34085039+poly000@users.noreply.github.com> Date: Wed, 25 Aug 2021 10:43:23 +0800 Subject: [PATCH 124/217] Fixing grammar and spelling mistakes (#270) --- CONTRIBUTING.md | 12 ++++++------ README.md | 2 +- additional_resources/design-principles.md | 12 ++++++------ anti_patterns/borrow_clone.md | 2 +- functional/generics-type-classes.md | 4 ++-- idioms/coercion-arguments.md | 2 +- idioms/default.md | 2 +- idioms/deref.md | 2 +- idioms/dtor-finally.md | 18 +++++++++--------- idioms/mem-replace.md | 6 +++--- idioms/option-iter.md | 2 +- idioms/pass-var-to-closure.md | 2 +- idioms/priv-extend.md | 2 +- idioms/rustdoc-init.md | 4 ++-- intro.md | 2 +- patterns/behavioural/command.md | 2 +- patterns/behavioural/interpreter.md | 2 +- patterns/behavioural/newtype.md | 2 +- patterns/behavioural/strategy.md | 4 ++-- patterns/creational/builder.md | 2 +- patterns/creational/fold.md | 2 +- patterns/ffi/export.md | 6 +++--- patterns/index.md | 2 +- 23 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 469d94a0..41383c59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,8 +16,8 @@ If you want to be part of this effort here are some ways you can participate: ## Discussion board -If you have a question or an idea regarding certain content but you want to -have feedback of fellow community members and you think it may not be +If you have a question or an idea regarding certain content, but you want to +have feedback of fellow community members, and you think it may not be appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). ## Writing a new article @@ -29,14 +29,14 @@ there is an existing discussion or if someone is already working on that topic: - [All issues](https://github.com/rust-unofficial/patterns/issues), - [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) -If you don't find an issue regarding your topic and you are sure it is not more +If you don't find an issue regarding your topic, and you are sure it is not more feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) -please open a new issue, so we can discuss about the ideas and future content +please open a new issue, so we can discuss the ideas and future content of the article together and maybe give some feedback/input on it. When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) into the appropriate directory and start editing it. You may not want to fill -out every section and remove it or you might want to add extra sections. +out every section and remove it, or you might want to add extra sections. Consider writing your article in a way that has a low barrier of entry so also [Rustlings](https://github.com/rust-lang/rustlings) can follow and understand @@ -53,7 +53,7 @@ in your article. Don't forget to add your new article to the `SUMMARY.md` to let it be rendered to the book. -Please make `Draft Pull requests` early so we can follow your progress and can +Please make `Draft Pull requests` early, so we can follow your progress and can give early feedback (see the following section). ## Style guide diff --git a/README.md b/README.md index 8831856e..3d960a8f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). ## Contributing -You are missing content in this repository that can be helpful for others and +You are missing content in this repository that can be helpful for others, and you are eager to explain it? Awesome! We are always happy about new contributions (e.g. elaboration or corrections on certain topics) to this project. diff --git a/additional_resources/design-principles.md b/additional_resources/design-principles.md index b764d368..d20ff914 100644 --- a/additional_resources/design-principles.md +++ b/additional_resources/design-principles.md @@ -56,7 +56,7 @@ unauthorized parties' direct access to them. “Functions should not produce abstract side effects...only commands (procedures) will be permitted to produce side effects.” - Bertrand Meyer: -Object Oriented Software Construction +Object-Oriented Software Construction ## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) @@ -66,30 +66,30 @@ to behave. The behavior should not astonish or surprise users ## Linguistic-Modular-Units “Modules must correspond to syntactic units in the language used.” - Bertrand -Meyer: Object Oriented Software Construction +Meyer: Object-Oriented Software Construction ## Self-Documentation “The designer of a module should strive to make all information about the -module part of the module itself.” - Bertrand Meyer: Object Oriented Software +module part of the module itself.” - Bertrand Meyer: Object-Oriented Software Construction ## Uniform-Access “All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or -through computation.” - Bertrand Meyer: Object Oriented Software Construction +through computation.” - Bertrand Meyer: Object-Oriented Software Construction ## Single-Choice “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: -Object Oriented Software Construction +Object-Oriented Software Construction ## Persistence-Closure “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 +that has not yet been retrieved.” - Bertrand Meyer: Object-Oriented Software Construction diff --git a/anti_patterns/borrow_clone.md b/anti_patterns/borrow_clone.md index 4ee96789..d44361d7 100644 --- a/anti_patterns/borrow_clone.md +++ b/anti_patterns/borrow_clone.md @@ -54,7 +54,7 @@ Even though `.clone()` is an indication of a bad pattern, sometimes - the developer is still new to ownership - the code doesn't have great speed or memory constraints (like hackathon projects or prototypes) -- satisfying the borrow checker is really complicated and you prefer to +- satisfying the borrow checker is really complicated, and you prefer to optimize readability over performance If an unnecessary clone is suspected, The [Rust Book's chapter on Ownership](https://doc.rust-lang.org/book/ownership.html) diff --git a/functional/generics-type-classes.md b/functional/generics-type-classes.md index 9999e921..01584f3f 100644 --- a/functional/generics-type-classes.md +++ b/functional/generics-type-classes.md @@ -25,7 +25,7 @@ This is called **monomorphization**, where different types are created from generic parameters: different values for the generic type cause different types, and different types can have different `impl` blocks. -In object oriented languages, classes can inherit behavior from their parents. +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. @@ -259,7 +259,7 @@ It is also used by several popular crates to allow API flexibility: * 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 techinque. [^6] + concept, and a slightly different technique. [^6] [^1]: See: [impl From\ for Vec\]( https://doc.rust-lang.org/stable/src/std/ffi/c_str.rs.html#799-801) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index 1c13aac3..b6f58936 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -7,7 +7,7 @@ when you are deciding which argument type to use for a function argument. In this way, the function will accept more input types. This is not limited to slice-able or fat pointer types. -In fact you should always prefer using the __borrowed type__ over +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`. diff --git a/idioms/default.md b/idioms/default.md index 85b29f0c..1baf58cd 100644 --- a/idioms/default.md +++ b/idioms/default.md @@ -46,7 +46,7 @@ fn main() { conf.check = true; println!("conf = {:#?}", conf); - // partial initalization with default values, creates the same instance + // partial initialization with default values, creates the same instance let conf1 = MyConfiguration { check: true, ..Default::default() diff --git a/idioms/deref.md b/idioms/deref.md index ef1530da..8479af97 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -61,7 +61,7 @@ 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 multiply referenced. +it can be multiplied referenced. Most smart pointers (e.g., `Foo`) implement `Deref`. However, collections will usually dereference to a custom type. `[T]` and `str` have some diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index cbcd8186..ea8024e8 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -3,7 +3,7 @@ ## Description 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 +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. ## Example @@ -41,7 +41,7 @@ Panicking will also exit a function early. ## Advantages -Code in destructors will (nearly) always be run - copes with panics, early +Code in destructors will (nearly) be always run - copes with panics, early returns, etc. ## Disadvantages @@ -49,7 +49,7 @@ returns, etc. 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 finalisers where it is +thread. Therefore, destructors cannot be relied on as finalizers where it is absolutely essential that finalisation happens. This pattern introduces some hard to notice, implicit code. Reading a function @@ -61,16 +61,16 @@ Requiring an object and `Drop` impl just for finalisation is heavy on boilerplat ## Discussion There is some subtlety about how exactly to store the object used as a -finaliser. It must be kept alive until the end of the function and must then be +finalizer. It must be kept alive until the end of the function and must then 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 finaliser can +`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 -finaliser should not be moved or returned. +finalizer should not be moved or returned. -The finaliser must be assigned into a variable, otherwise it will be destroyed +The finalizer must be assigned into a variable, otherwise it will be destroyed immediately, rather than when it goes out of scope. The variable name must start -with `_` if the variable is only used as a finaliser, otherwise the compiler -will warn that the finaliser is never used. However, do not call the variable +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. In Rust, destructors are run when an object goes out of scope. This happens diff --git a/idioms/mem-replace.md b/idioms/mem-replace.md index d03c9d5c..b1ea07f1 100644 --- a/idioms/mem-replace.md +++ b/idioms/mem-replace.md @@ -63,9 +63,9 @@ its parts to decide what to do next. In the second phase we may conditionally change the value (as in the example above). 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 +*something* must be there.) We could of course `.clone()` name and put the clone into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy -the borrow checker](../anti_patterns/borrow_clone.md) antipattern. Anyway, we +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. `mem::take` lets us swap out the value, replacing it with it's default value, @@ -110,4 +110,4 @@ like Indiana Jones, replacing the artifact with a bag of sand. ## See also This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md) -antipattern in a specific case. +anti-pattern in a specific case. diff --git a/idioms/option-iter.md b/idioms/option-iter.md index e1c74bd0..e11d6694 100644 --- a/idioms/option-iter.md +++ b/idioms/option-iter.md @@ -3,7 +3,7 @@ ## Description `Option` can be viewed as a container that contains either zero or one -elements. In particular, it implements the `IntoIterator` trait, and as such +element. In particular, it implements the `IntoIterator` trait, and as such can be used with generic code that needs such a type. ## Examples diff --git a/idioms/pass-var-to-closure.md b/idioms/pass-var-to-closure.md index 81e5b51c..b6a351dd 100644 --- a/idioms/pass-var-to-closure.md +++ b/idioms/pass-var-to-closure.md @@ -48,7 +48,7 @@ let closure = move || { ## Advantages Copied data are grouped together with closure definition, so their purpose is -more clear and they will be dropped immediately even if they are not consumed +more clear, and they will be dropped immediately even if they are not consumed by closure. Closure uses same variable names as surrounding code whether data are copied or diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index d0c115b6..2b76665f 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -30,7 +30,7 @@ fn main(s: a::S) { 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 of the fields and use `..` in the pattern, +pattern. The client could name some fields and use `..` in the pattern, in which case 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. diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 96df84e8..57ec315d 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -44,7 +44,7 @@ impl Connection { ## Example -Instead of typing all of this boiler plate to create an `Connection` and +Instead of typing all of this boilerplate to create an `Connection` and `Request` it is easier to just create a wrapping helper function which takes them as arguments: @@ -71,7 +71,7 @@ impl Connection { ``` **Note** in the above example the line `assert!(response.is_ok());` will not -actually run while testing because it is inside of a function which is never +actually run while testing because it is inside a function which is never invoked. ## Advantages diff --git a/intro.md b/intro.md index da507a62..7fd54029 100644 --- a/intro.md +++ b/intro.md @@ -9,7 +9,7 @@ If you are interested in contributing to this book, check out the When developing programs, we have to solve many problems. A program can be viewed as a solution to a problem. -It can also be viewed as a collection of solutions to many different problems. +It can also be viewed as a collection of solutions to many problems. All of these solutions work together to solve a bigger problem. ## Design patterns in Rust diff --git a/patterns/behavioural/command.md b/patterns/behavioural/command.md index c878963a..1e0ae263 100644 --- a/patterns/behavioural/command.md +++ b/patterns/behavioural/command.md @@ -205,7 +205,7 @@ fn main() { If our commands are small and may be defined as functions or passed as a 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 seperate module then using trait objects would be +and variables defined as seperated 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 diff --git a/patterns/behavioural/interpreter.md b/patterns/behavioural/interpreter.md index 5f97558e..349d8ce0 100644 --- a/patterns/behavioural/interpreter.md +++ b/patterns/behavioural/interpreter.md @@ -23,7 +23,7 @@ operations `+`, `-`. For example, the expression `2 + 4` is translated into ## Context Free Grammar for our problem -Our task is translate infix expressions into postfix ones. Let's define a context +Our task is translated infix expressions into postfix ones. Let's define a context free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-`, where: diff --git a/patterns/behavioural/newtype.md b/patterns/behavioural/newtype.md index 6b023747..fb2e8665 100644 --- a/patterns/behavioural/newtype.md +++ b/patterns/behavioural/newtype.md @@ -1,7 +1,7 @@ # Newtype What if in some cases we want a type to behave similar to another type or -enforce some behaviour at compile time where using only type aliases would +enforce some behaviour at compile time when using only type aliases would not be enough? For example, if we want to create a custom `Display` implementation for `String` diff --git a/patterns/behavioural/strategy.md b/patterns/behavioural/strategy.md index e00d2c92..a1ea98da 100644 --- a/patterns/behavioural/strategy.md +++ b/patterns/behavioural/strategy.md @@ -8,7 +8,7 @@ It also allows to decouple software modules through [Dependency Inversion](https The basic idea behind the Strategy pattern is that, given an algorithm 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. +level, and we separate the specific algorithm’s implementation into different parts. In this way, a client using the algorithm may choose a specific implementation, while the general algorithm workflow remains the same. In other words, the abstract @@ -21,7 +21,7 @@ This is why we call it "Dependency Inversion". 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 +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 completly new format, or just modify one of the existing formats. diff --git a/patterns/creational/builder.md b/patterns/creational/builder.md index 8b3e494e..a24cd3c4 100644 --- a/patterns/creational/builder.md +++ b/patterns/creational/builder.md @@ -62,7 +62,7 @@ fn builder_test() { ## Motivation -Useful when you would otherwise require many different constructors or where +Useful when you would otherwise require many constructors or where construction has side effects. ## Advantages diff --git a/patterns/creational/fold.md b/patterns/creational/fold.md index 8d8e0ccd..13eab838 100644 --- a/patterns/creational/fold.md +++ b/patterns/creational/fold.md @@ -102,7 +102,7 @@ reused; however, a node must be cloned even if unchanged, which can be expensive. 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, +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. diff --git a/patterns/ffi/export.md b/patterns/ffi/export.md index 8b96a17e..8b5a4f06 100644 --- a/patterns/ffi/export.md +++ b/patterns/ffi/export.md @@ -43,7 +43,7 @@ The POSIX standard defines the API to access an on-file database, known as [DBM] It is an excellent example of an "object-based" API. Here is the definition in C, which hopefully should be easy to read for those -involved in FFI. The commentary below should help explaining it for those who +involved in FFI. The commentary below should help explain it for those who miss the subtleties. ```C @@ -105,7 +105,7 @@ 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 is what this best practice is about, and the key +do it wrong. Minimizing those are what this best practice is about, and the key is to *transfer ownership of everything that is transparent*. ## Advantages @@ -229,7 +229,7 @@ datum dbm_firstkey(DBM *); datum dbm_nextkey(DBM *); ``` -Thus, all of the lifetimes were bound together, and such unsafety was prevented. +Thus, all the lifetimes were bound together, and such unsafety was prevented. ## Disadvantages diff --git a/patterns/index.md b/patterns/index.md index 1bdda780..e43d1e5f 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -13,7 +13,7 @@ about a programming language. ## Design patterns in Rust -Rust has many very unique features. These features give us great benefit by removing +Rust has many unique features. These features give us great benefit by removing whole classes of problems. Some of them are also patterns that are _unique_ to Rust. ## YAGNI From 241dfb7cdd4a118a0a6ad4d4fdf4c4d13fa2e69c Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 25 Aug 2021 04:48:01 +0200 Subject: [PATCH 125/217] Update mdbook to v0.4.12 (#271) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index a084ce2e..8ece8165 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.8 +MDBOOK_VERSION=0.4.12 From fa29385292def63efb265879889d2dacbfa9fc00 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 25 Aug 2021 04:58:14 +0200 Subject: [PATCH 126/217] Updating main branch name (#272) --- .github/workflows/ci.yml | 2 +- .github/workflows/gh-pages.yml | 2 +- .github/workflows/url-check-on-change.yml | 3 ++- .github/workflows/url-check-periodic.yml | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 753412bc..7e44ee86 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: Continuous Integration on: push: - branches: [master] + branches: [main] pull_request: jobs: diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index b0b8e2f7..913e2801 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -3,7 +3,7 @@ name: github pages on: push: branches: - - master + - main jobs: deploy: diff --git a/.github/workflows/url-check-on-change.yml b/.github/workflows/url-check-on-change.yml index af15a537..c72431ab 100644 --- a/.github/workflows/url-check-on-change.yml +++ b/.github/workflows/url-check-on-change.yml @@ -2,7 +2,7 @@ name: Check Markdown links on: push: - branches: [master] + branches: [main] pull_request: jobs: @@ -16,3 +16,4 @@ jobs: use-quiet-mode: 'yes' config-file: '.github/workflows/url-check-config.json' check-modified-files-only: 'yes' + base-branch: 'main' diff --git a/.github/workflows/url-check-periodic.yml b/.github/workflows/url-check-periodic.yml index 402609b5..76b3ad7d 100644 --- a/.github/workflows/url-check-periodic.yml +++ b/.github/workflows/url-check-periodic.yml @@ -15,3 +15,4 @@ jobs: use-verbose-mode: 'yes' use-quiet-mode: 'yes' config-file: '.github/workflows/url-check-config.json' + base-branch: 'main' From 567a1f16fbca96f77e38740587cbc410335ab893 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Tue, 31 Aug 2021 20:28:30 -0400 Subject: [PATCH 127/217] Updated extensibility to discuss non_exhaustive (#135) --- idioms/priv-extend.md | 122 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 23 deletions(-) diff --git a/idioms/priv-extend.md b/idioms/priv-extend.md index 2b76665f..2a14fdb4 100644 --- a/idioms/priv-extend.md +++ b/idioms/priv-extend.md @@ -1,46 +1,122 @@ -# Privacy for extensibility +# `#[non_exhaustive]` and private fields for extensibility ## Description -Use a private field to ensure that a struct is extensible without breaking -stability guarantees. +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 +compatibility. + +Rust offers two solutions to this problem: + +- 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). + +- You may add a private field to a struct to prevent it from being directly + instantiated or matched against (see Alternative) ## Example -```rust,ignore +```rust mod a { // Public struct. + #[non_exhaustive] pub struct S { pub foo: i32, - // Private field. - bar: i32, + } + + #[non_exhaustive] + pub enum AdmitMoreVariants { + VariantA, + VariantB, + #[non_exhaustive] + VariantC { a: String } } } -fn main(s: a::S) { - // Because S::bar is private, it cannot be named here and we must use `..` - // in the pattern. +fn print_matched_variants(s: a::S) { + // Because S is `#[non_exhaustive]`, it cannot be named here and + // we must use `..` in the pattern. let a::S { foo: _, ..} = s; -} + + let some_enum = a::AdmitMoreVariants::VariantA; + match some_enum { + a::AdmitMoreVariants::VariantA => println!("it's an A"), + a::AdmitMoreVariants::VariantB => println!("it's a b"), + + // .. required because this variant is non-exhaustive as well + a::AdmitMoreVariants::VariantC { a, .. } => println!("it's a c"), + // The wildcard match is required because more variants may be + // added in the future + _ => println!("it's a new variant") + } +} ``` -## Discussion +## Alternative: `Private fields` for structs + +`#[non_exhaustive]` only works across crate boundaries. +Within a crate, the private field method may be used. 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 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. +pattern. +The client could name some fields and use `..` in the pattern, in which case 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. The downside of this approach is that you might need to add an otherwise 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. - -If Rust allowed private variants of enums, we could use the same trick to make -adding a variant to an enum backwards compatible. The problem there is exhaustive -match expressions. A private variant would force clients to have a `_` wildcard -pattern. A common way to implement this instead is using the [`#[non_exhaustive]`]() -attribute. +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. + +```rust +pub struct S { + pub a: i32, + // Because `b` is private, you cannot match on `S` without using `..` and `S` + // cannot be directly instantiated or matched against + _b: () +} +``` + +## Discussion + +On `struct`s, `#[non_exhaustive]` allows adding additional fields in a 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. + +`#[non_exhaustive]` can be applied to enum variants as well. +A `#[non_exhaustive]` variant behaves in the same way as a `#[non_exhaustive]` struct. + +Use this deliberately and with caution: incrementing the major version when 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. + +### Disadvantages + +`#[non_exhaustive]` can make your code much less ergonomic to use, 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. + +When `#[non_exhaustive]` is applied to `enum`s, it forces clients to handle 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. + +## See also + +- [RFC introducing #[non_exhaustive] attribute for enums and structs](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md) From 7e9616978f81e44f1a6a5e7577567994c87585d4 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 15 Sep 2021 14:49:01 +0300 Subject: [PATCH 128/217] Escape underscores in a link in functional/generics-type-classes.md (#273) Previously they were parsed as italic modifiers. --- functional/generics-type-classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functional/generics-type-classes.md b/functional/generics-type-classes.md index 01584f3f..f31bf509 100644 --- a/functional/generics-type-classes.md +++ b/functional/generics-type-classes.md @@ -267,7 +267,7 @@ https://doc.rust-lang.org/stable/src/std/ffi/c_str.rs.html#799-801) [^2]: See: [impl\ From\\> for BinaryHeap\]( https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) -[^3]: See: [impl\<'_\> ToString for Cow\<'_, str>]( +[^3]: See: [impl\<'\_\> ToString for Cow\<'\_, str>]( https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) [^4]: Example: From 66d7e6c7daea2b6cf50f6cb230c7203ece0d8678 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sat, 2 Oct 2021 11:52:00 +0200 Subject: [PATCH 129/217] deref: fix typo (#275) --- idioms/deref.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/deref.md b/idioms/deref.md index 8479af97..0c1712e4 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -61,7 +61,7 @@ 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 multiplied referenced. +it can be referenced multiple times. Most smart pointers (e.g., `Foo`) implement `Deref`. However, collections will usually dereference to a custom type. `[T]` and `str` have some From 39a2f36eab17abd814b9875703f98e3e32a257ff Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 18 Oct 2021 14:27:52 +0200 Subject: [PATCH 130/217] deny-warnings: remove contradiction with rustc doc (#282) --- anti_patterns/deny-warnings.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index c4efd726..84d4d00b 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -37,9 +37,7 @@ All this conspires to potentially break the build whenever something changes. Furthermore, crates that supply additional lints (e.g. [rust-clippy]) can no longer be used unless the annotation is removed. This is mitigated with [--cap-lints]. The `--cap-lints=warn` command line argument, turns all `deny` -lint errors into warnings. But be aware that `forbid` lints are stronger than -`deny` hence the 'forbid' level cannot be overridden to be anything lower than -an error. As a result `forbid` lints will still stop compilation. +lint errors into warnings. ## Alternatives From fa8e72298e7d478190f8b23d66c1ca03b564dd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=99=AB=20Christian=20Krause=20=E2=99=AB?= Date: Sun, 21 Nov 2021 23:37:25 +0100 Subject: [PATCH 131/217] [idioms/ctor] adds default constructor section (#280) Replaced the `Vec` example with `Second`. This is easier to comprehend compared to the more complex `Vec` example. It's also testable because it doesn't rely on `RawVec`. Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- idioms/ctor.md | 114 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 21 deletions(-) diff --git a/idioms/ctor.md b/idioms/ctor.md index d9c45131..dbb74698 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -3,34 +3,106 @@ ## Description Rust does not have constructors as a language construct. Instead, the -convention is to use a static `new` method to create an object. +convention is to use an [associated function][] `new` to create an object: -## Example +```rust +/// Time in seconds. +/// +/// # Example +/// +/// ``` +/// let s = Second::new(42); +/// assert_eq!(42, s.value()); +/// ``` +pub struct Second { + value: u64 +} + +impl Second { + // Constructs a new instance of [`Second`]. + // Note this is an associated function - no self. + pub fn new(value: u64) -> Self { + Self { value } + } + + /// Returns the value in seconds. + pub fn value(&self) -> u64 { + self.value + } +} +``` + +## Default Constructors + +Rust supports default constructors with the [`Default`][std-default] trait: -```rust,ignore -// A Rust vector, see liballoc/vec.rs -pub struct Vec { - buf: RawVec, - len: usize, +```rust +/// Time in seconds. +/// +/// # Example +/// +/// ``` +/// let s = Second::default(); +/// assert_eq!(0, s.value()); +/// ``` +pub struct Second { + value: u64 +} + +impl Second { + /// Returns the value in seconds. + pub fn value(&self) -> u64 { + self.value + } } -impl Vec { - // Constructs a new, empty `Vec`. - // Note this is a static method - no self. - // This constructor doesn't take any arguments, but some might in order to - // properly initialise an object - pub fn new() -> Vec { - // Create a new Vec with fields properly initialised. - Vec { - // Note that here we are calling RawVec's constructor. - buf: RawVec::new(), - len: 0, - } +impl Default for Second { + fn default() -> Self { + Self { value: 0 } } } ``` +`Default` can also be derived if all types of all fields implement `Default`, +like they do with `Second`: + +```rust +/// Time in seconds. +/// +/// # Example +/// +/// ``` +/// let s = Second::default(); +/// assert_eq!(0, s.value()); +/// ``` +#[derive(Default)] +pub struct Second { + value: u64 +} + +impl Second { + /// Returns the value in seconds. + pub fn value(&self) -> u64 { + self.value + } +} +``` + +**Note:** When implementing `Default` for a type, it is neither required nor +recommended to also provide an associated function `new` without arguments. + +**Hint:** The advantage of implementing or deriving `Default` is that your type +can now be used where a `Default` implementation is required, most prominently, +any of the [`*or_default` functions in the standard library][std-or-default]. + ## See also -The [builder pattern](../patterns/creational/builder.md) for constructing objects -where there are multiple configurations. +- The [default idiom](default.md) for a more in-depth description of the + `Default` trait. + +- The [builder pattern](../patterns/creational/builder.md) for constructing + objects where there are multiple configurations. + +[associated function]: https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions +[std-default]: https://doc.rust-lang.org/stable/std/default/trait.Default.html +[std-or-default]: https://doc.rust-lang.org/stable/std/?search=or_default From 044d36579ff03147a1f13564a345ac8fbebfb6f8 Mon Sep 17 00:00:00 2001 From: Anatol Ulrich <45840+spookyvision@users.noreply.github.com> Date: Thu, 25 Nov 2021 04:04:41 +0100 Subject: [PATCH 132/217] Formatting fixes to unsafe-mods.md (#283) --- patterns/structural/unsafe-mods.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/patterns/structural/unsafe-mods.md b/patterns/structural/unsafe-mods.md index 682bd631..41737023 100644 --- a/patterns/structural/unsafe-mods.md +++ b/patterns/structural/unsafe-mods.md @@ -22,11 +22,12 @@ of the inner module ## Examples * The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations - in submodules, presenting a safe interface to users. * `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. + in submodules, presenting a safe interface to users. +* `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. ## See also From 11a0a13dbab7197c8ac6e13376c27a809d23d53e Mon Sep 17 00:00:00 2001 From: Sven Assmann Date: Tue, 14 Dec 2021 09:53:34 +0100 Subject: [PATCH 133/217] chore: use `Self` instead of the struct name (#284) --- patterns/behavioural/newtype.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/behavioural/newtype.md b/patterns/behavioural/newtype.md index fb2e8665..549c923e 100644 --- a/patterns/behavioural/newtype.md +++ b/patterns/behavioural/newtype.md @@ -35,7 +35,7 @@ impl Bar { // Constructor. pub fn new( //.. - ) -> Bar { + ) -> Self { //.. From dca0dfdc29d8f3252c3787c2af5ba75e6466b4d5 Mon Sep 17 00:00:00 2001 From: alsotang Date: Thu, 16 Dec 2021 23:10:24 +0800 Subject: [PATCH 134/217] Update coercion-arguments.md (#286) align the type --- idioms/coercion-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index b6f58936..caa37c9d 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -21,7 +21,7 @@ coerce to a `&str` whenever the function is invoked. For this example, we will illustrate some differences for using `&String` as a function argument versus using a `&str`, but the ideas apply as well to using -`&Vec` versus using a `&[T]` or using a `&T` versus a `&Box`. +`&Vec` versus using a `&[T]` or using a `&Box` versus a `&T`. 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 From bcf1a7aeae88c667f73d058e068b6279ffd57952 Mon Sep 17 00:00:00 2001 From: poly000 <34085039+poly000@users.noreply.github.com> Date: Sat, 8 Jan 2022 23:18:44 +0800 Subject: [PATCH 135/217] fix typo (#289) --- patterns/behavioural/strategy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/behavioural/strategy.md b/patterns/behavioural/strategy.md index a1ea98da..a5aac8d0 100644 --- a/patterns/behavioural/strategy.md +++ b/patterns/behavioural/strategy.md @@ -22,7 +22,7 @@ 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 completly new +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. ## Example From 90484a2387d96a6a93f00c9cadd02f10d2f4c4cf Mon Sep 17 00:00:00 2001 From: poly000 <34085039+poly000@users.noreply.github.com> Date: Sat, 15 Jan 2022 07:20:48 +0800 Subject: [PATCH 136/217] fix comment in 'Clone to stasify borrow checker' (#291) --- anti_patterns/borrow_clone.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/anti_patterns/borrow_clone.md b/anti_patterns/borrow_clone.md index d44361d7..f5806aa2 100644 --- a/anti_patterns/borrow_clone.md +++ b/anti_patterns/borrow_clone.md @@ -17,14 +17,14 @@ let mut x = 5; // Borrow `x` -- but clone it first let y = &mut (x.clone()); -// perform some action on the borrow to prevent rust from optimizing this -//out of existence -*y += 1; - // without the x.clone() two lines prior, this line would fail on compile as // x has been borrowed // thanks to x.clone(), x was never borrowed, and this line will run. println!("{}", x); + +// perform some action on the borrow to prevent rust from optimizing this +//out of existence +*y += 1; ``` ## Motivation From 2577a11869e00c8df6509264aaed5c4f56a784aa Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 18 Jan 2022 00:53:40 +0800 Subject: [PATCH 137/217] Add Link to zh-CN translation (#293) --- SUMMARY.md | 1 + translations.md | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 translations.md diff --git a/SUMMARY.md b/SUMMARY.md index abce59cb..aa85661d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,7 @@ # Summary - [Introduction](./intro.md) + - [Translations](./translations.md) - [Idioms](./idioms/index.md) - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - [Concatenating Strings with `format!`](./idioms/concat-format.md) diff --git a/translations.md b/translations.md new file mode 100644 index 00000000..8c89dea2 --- /dev/null +++ b/translations.md @@ -0,0 +1,6 @@ +# Translations + +- [简体中文](https://fomalhauthmj.github.io/patterns/) + +If you want to add a translation, please open an issue in the +[main repository](https://github.com/rust-unofficial/patterns). From cb591acb56260a5bc8824c9a51d017673775dc64 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Mon, 17 Jan 2022 21:53:32 +0100 Subject: [PATCH 138/217] Update .env (#294) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 8ece8165..6ce00342 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.12 +MDBOOK_VERSION=0.4.15 From d510bc2431440313d6d5173c129f56267eb31448 Mon Sep 17 00:00:00 2001 From: Marko <83985775+MarkoM-dot@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:32:07 +0100 Subject: [PATCH 139/217] Changes to introductory text. (#299) * change to introductory text on design patterns with a very brief description * minor textual adjustments * shortened line length * markdown fixes * Update intro.md removed redundancy Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- intro.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/intro.md b/intro.md index 7fd54029..529d6146 100644 --- a/intro.md +++ b/intro.md @@ -7,10 +7,17 @@ If you are interested in contributing to this book, check out the ## Design patterns -When developing programs, we have to solve many problems. -A program can be viewed as a solution to a problem. -It can also be viewed as a collection of solutions to many problems. -All of these solutions work together to solve a bigger problem. +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. + +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 to use, making them an excellent tool for effective +communication when problem-solving in teams. ## Design patterns in Rust From 482c2b8720060974bcad40a6396097c4db0e6f0d Mon Sep 17 00:00:00 2001 From: Andrew Sonin Date: Wed, 9 Mar 2022 11:08:25 +0300 Subject: [PATCH 140/217] Fix typo (#300) `Iterator::filter_map` is analogous to `Iterator::map`, not `Iterator::flat_map` --- idioms/option-iter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idioms/option-iter.md b/idioms/option-iter.md index e11d6694..a3e8adda 100644 --- a/idioms/option-iter.md +++ b/idioms/option-iter.md @@ -50,7 +50,7 @@ iterator which yields exactly one element. It's a more readable alternative to `Some(foo).into_iter()`. * [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) - is a version of [`Iterator::flat_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_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`. * The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions From b440ed2dba98529e75272f6e0372151e0a542e80 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:54:57 +0100 Subject: [PATCH 141/217] idioms: intro improvements (#304) --- idioms/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/idioms/index.md b/idioms/index.md index e03fcfa0..22ebed6a 100644 --- a/idioms/index.md +++ b/idioms/index.md @@ -1,14 +1,14 @@ # Idioms [Idioms](https://en.wikipedia.org/wiki/Programming_idiom) are commonly used -styles and patterns largely agreed upon by a community. They are guidelines. -Writing idiomatic code allows other developers to understand what is happening -because they are familiar with the form that it has. +styles, guidelines and patterns largely agreed upon by a community. +Writing idiomatic code allows other developers to understand better what is +happening. -The computer understands the machine code that is generated by the compiler. -The language is therefore mostly beneficial to the developer. -So, since we have this abstraction layer, why not put it to good use and make -it simple? +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? 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 From 48b1bf51ef71be494fd1c26143169763706a2f9c Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:57:10 +0100 Subject: [PATCH 142/217] ci: update actions/checkout version (#302) --- .github/workflows/ci.yml | 6 +++--- .github/workflows/gh-pages.yml | 2 +- .github/workflows/url-check-on-change.yml | 2 +- .github/workflows/url-check-periodic.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e44ee86..b46c7637 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: deploy-test: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Read .env id: mdbook-version @@ -27,7 +27,7 @@ jobs: doc-test: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Read .env id: mdbook-version @@ -45,7 +45,7 @@ jobs: markdown-lint: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Lint all files recursively uses: avto-dev/markdown-lint@v1 with: diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 913e2801..78d1edb2 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -9,7 +9,7 @@ jobs: deploy: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Read .env id: mdbook-version diff --git a/.github/workflows/url-check-on-change.yml b/.github/workflows/url-check-on-change.yml index c72431ab..c3c571d6 100644 --- a/.github/workflows/url-check-on-change.yml +++ b/.github/workflows/url-check-on-change.yml @@ -9,7 +9,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: use-verbose-mode: 'yes' diff --git a/.github/workflows/url-check-periodic.yml b/.github/workflows/url-check-periodic.yml index 76b3ad7d..e5d7c075 100644 --- a/.github/workflows/url-check-periodic.yml +++ b/.github/workflows/url-check-periodic.yml @@ -9,7 +9,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: use-verbose-mode: 'yes' From 78735669afeffe6e925a10625b52bd18a085793f Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 17 Mar 2022 14:02:20 +0100 Subject: [PATCH 143/217] intro: improve "design patterns in rust" section (#303) --- intro.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/intro.md b/intro.md index 529d6146..71c8f88b 100644 --- a/intro.md +++ b/intro.md @@ -16,25 +16,25 @@ are generically applicable. 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 to use, making them an excellent tool for effective +language for developers, making them an excellent tool for effective communication when problem-solving in teams. ## Design patterns in Rust -There are many problems that share the same form. -Due to the fact that Rust is not object-oriented, design patterns vary with -respect to other object-oriented programming languages. -While the details are different, since they have the same form they can be -solved using the same fundamental methods: - -- [Design patterns](./patterns/index.md) are methods to solve common problems - when writing software. -- [Anti-patterns](./anti_patterns/index.md) are methods to solve these same - common problems. However, while design patterns give us benefits, +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: + +- [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. +- [Design patterns](./patterns/index.md): methods to solve common problems + when coding. +- [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. -- [Idioms](./idioms/index.md) are guidelines to follow when coding. - They are social norms of the community. - You can break them, but if you do you should have a good reason for it. - -TODO: Mention why Rust is a bit special - functional elements, type system, -borrow checker From 465ed6c860566da506003e960888c7051c3ff99c Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 4 Apr 2022 22:46:53 +0200 Subject: [PATCH 144/217] patterns: remove TODO item (#305) --- patterns/index.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/patterns/index.md b/patterns/index.md index e43d1e5f..1718174c 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -18,14 +18,11 @@ whole classes of problems. Some of them are also patterns that are _unique_ to R ## YAGNI -If you're not familiar with it, YAGNI is an acronym that stands for -`You Aren't Going to Need It`. It's an important 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. > The best code I ever wrote was code I never wrote. If we apply YAGNI to design patterns, we see that the features of Rust allow 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). - -TODO: Maybe include some code to illustrate the traits. From 662a519128b0e8176ee8ab03152ff7f2a546d8cd Mon Sep 17 00:00:00 2001 From: hafeoz <95505675+hafeoz@users.noreply.github.com> Date: Thu, 26 May 2022 22:59:50 +0100 Subject: [PATCH 145/217] Change lints hyphen to underscore (#308) --- anti_patterns/deny-warnings.md | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/anti_patterns/deny-warnings.md b/anti_patterns/deny-warnings.md index 84d4d00b..1dae9d29 100644 --- a/anti_patterns/deny-warnings.md +++ b/anti_patterns/deny-warnings.md @@ -57,35 +57,35 @@ 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): ```rust,ignore -#[deny(bad-style, - const-err, - dead-code, - improper-ctypes, - non-shorthand-field-patterns, - no-mangle-generic-items, - overflowing-literals, - path-statements , - patterns-in-fns-without-body, - private-in-public, - unconditional-recursion, +#![deny(bad_style, + const_err, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + private_in_public, + unconditional_recursion, unused, - unused-allocation, - unused-comparisons, - unused-parens, - while-true)] + unused_allocation, + unused_comparisons, + unused_parens, + while_true)] ``` In addition, the following `allow`ed lints may be a good idea to `deny`: ```rust,ignore -#[deny(missing-debug-implementations, - missing-docs, - trivial-casts, - trivial-numeric-casts, - unused-extern-crates, - unused-import-braces, - unused-qualifications, - unused-results)] +#![deny(missing_debug_implementations, + missing_docs, + trivial_casts, + trivial_numeric_casts, + unused_extern_crates, + unused_import_braces, + unused_qualifications, + unused_results)] ``` Some may also want to add `missing-copy-implementations` to their list. From c7be15d387b3a0ce450563ea8c0c9fbd658ca5e3 Mon Sep 17 00:00:00 2001 From: Carson Riker Date: Sat, 2 Jul 2022 09:09:56 -0400 Subject: [PATCH 146/217] Modified example sentences to make sense (#311) --- idioms/coercion-arguments.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/idioms/coercion-arguments.md b/idioms/coercion-arguments.md index caa37c9d..2ca63ab5 100644 --- a/idioms/coercion-arguments.md +++ b/idioms/coercion-arguments.md @@ -60,9 +60,9 @@ fn main() { ``` This works fine because we are passing a `&String` type as a parameter. -If we comment in the last two lines this example fails because a `&str` type -will not coerce to a `&String` type. We can fix this by simply modifying the -type for our argument. +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. For instance, if we change our function declaration to: From 7258b7175300ec13da92c465d39e79a4ab2fc9f5 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:18:55 +0200 Subject: [PATCH 147/217] update mdbook version to 0.4.18 (#309) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 6ce00342..cc3b07ca 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.15 +MDBOOK_VERSION=0.4.18 From 396ac0fbf0976dc3f361532582cd25b1d474bec1 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:21:03 +0200 Subject: [PATCH 148/217] ci: keep github actions up to date with dependabot (#307) --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..400d577e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + # Check for updates every Monday + schedule: + interval: "weekly" + open-pull-requests-limit: 10 From 049d49d353079763856b1f7d8a8f2d9b4fe75d34 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 29 Jul 2022 08:21:42 +0200 Subject: [PATCH 149/217] Update mdbook version to v0.4.21 (#317) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index cc3b07ca..5d502324 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.18 +MDBOOK_VERSION=0.4.21 From 21a29edf52cbc77639fa59153d4771ec96782c33 Mon Sep 17 00:00:00 2001 From: Tristan Otterpohl <82106086+Otterpohl@users.noreply.github.com> Date: Mon, 1 Aug 2022 03:39:54 +0100 Subject: [PATCH 150/217] Fixed minor typos, formatting, grammar issues, and outdated link (#318) * Fixed minor typos, formatting, grammar issues, and outdated link --- functional/generics-type-classes.md | 6 +++--- idioms/dtor-finally.md | 2 +- idioms/ffi/errors.md | 2 +- idioms/rustdoc-init.md | 6 +++--- idioms/temporary-mutability.md | 4 ++-- patterns/behavioural/interpreter.md | 20 ++++++++++---------- patterns/behavioural/newtype.md | 2 +- patterns/creational/builder.md | 5 ++--- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/functional/generics-type-classes.md b/functional/generics-type-classes.md index f31bf509..df80a08b 100644 --- a/functional/generics-type-classes.md +++ b/functional/generics-type-classes.md @@ -22,7 +22,7 @@ type system. 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, +generic parameters. Different values for the generic type cause different types, and different types can have different `impl` blocks. In object-oriented languages, classes can inherit behavior from their parents. @@ -31,7 +31,7 @@ particular members of a type class, but extra behavior as well. The nearest equivalent is the runtime polymorphism in Javascript and Python, where new members can be added to objects willy-nilly by any constructor. -Unlike those languages, however, all of Rust's additional methods can be type +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. @@ -262,7 +262,7 @@ It is also used by several popular crates to allow API flexibility: concept, and a slightly different technique. [^6] [^1]: See: [impl From\ for Vec\]( -https://doc.rust-lang.org/stable/src/std/ffi/c_str.rs.html#799-801) +https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811) [^2]: See: [impl\ From\\> for BinaryHeap\]( https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) diff --git a/idioms/dtor-finally.md b/idioms/dtor-finally.md index ea8024e8..45152905 100644 --- a/idioms/dtor-finally.md +++ b/idioms/dtor-finally.md @@ -41,7 +41,7 @@ Panicking will also exit a function early. ## Advantages -Code in destructors will (nearly) be always run - copes with panics, early +Code in destructors will (nearly) always be run - copes with panics, early returns, etc. ## Disadvantages diff --git a/idioms/ffi/errors.md b/idioms/ffi/errors.md index 59d0c912..99fc77f6 100644 --- a/idioms/ffi/errors.md +++ b/idioms/ffi/errors.md @@ -4,7 +4,7 @@ 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 a propogated through a full type. +captured and propogated through a full type. This best practice shows different kinds of error codes, and how to expose them in a usable way: diff --git a/idioms/rustdoc-init.md b/idioms/rustdoc-init.md index 57ec315d..64c1e5d4 100644 --- a/idioms/rustdoc-init.md +++ b/idioms/rustdoc-init.md @@ -2,7 +2,7 @@ ## Description -If a struct takes significant effort to initialize, when writing docs, it can be +If a struct takes significant effort to initialize when writing docs, it can be quicker to wrap your example with a helper function which takes the struct as an argument. @@ -44,8 +44,8 @@ impl Connection { ## Example -Instead of typing all of this boilerplate to create an `Connection` and -`Request` it is easier to just create a wrapping helper function which takes +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 them as arguments: ```rust,ignore diff --git a/idioms/temporary-mutability.md b/idioms/temporary-mutability.md index c6d51b3c..e630e102 100644 --- a/idioms/temporary-mutability.md +++ b/idioms/temporary-mutability.md @@ -6,8 +6,8 @@ Often it is necessary to prepare and process some data, but after that data are only inspected and never modified. The intention can be made explicit by redefining the mutable variable as immutable. -It can be done either by processing data within nested block or by redefining -variable. +It can be done either by processing data within a nested block or by redefining +the variable. ## Example diff --git a/patterns/behavioural/interpreter.md b/patterns/behavioural/interpreter.md index 349d8ce0..21cf4457 100644 --- a/patterns/behavioural/interpreter.md +++ b/patterns/behavioural/interpreter.md @@ -9,9 +9,9 @@ simple language. Basically, for any kind of problems we define: -- a [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language), -- a grammar for this language, -- an interpreter that solves the problem instances. +- A [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language), +- A grammar for this language, +- An interpreter that solves the problem instances. ## Motivation @@ -19,18 +19,18 @@ Our goal is to translate simple mathematical expressions into postfix expression (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 +`. +`2 4 +`. ## Context Free Grammar for our problem -Our task is translated infix expressions into postfix ones. Let's define a context +Our task is translating infix expressions into postfix ones. Let's define a context free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-`, where: -- terminal symbols: `0`, ..., `9`, `+`, `-` -- non-terminal symbols: `exp`, `term` -- start symbol is `exp` -- and the following are production rules +- Terminal symbols: `0`, `...`, `9`, `+`, `-` +- Non-terminal symbols: `exp`, `term` +- Start symbol is `exp` +- And the following are production rules ```ignore exp -> exp + term @@ -107,7 +107,7 @@ There may be a wrong perception that the Interpreter design pattern is about des 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 to define special syntax and rules +Rust language has `macro_rules!` that allow us to define special syntax and rules on how to expand this syntax into source code. In the following example we create a simple `macro_rules!` that computes diff --git a/patterns/behavioural/newtype.md b/patterns/behavioural/newtype.md index 549c923e..8df944f3 100644 --- a/patterns/behavioural/newtype.md +++ b/patterns/behavioural/newtype.md @@ -61,7 +61,7 @@ By using a newtype rather than exposing the implementation type as part of an API, it allows you to change implementation backwards compatibly. Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give -distinguishable `Miles` and `Kms`. +distinguishable `Miles` and `Kilometres`. ## Advantages diff --git a/patterns/creational/builder.md b/patterns/creational/builder.md index a24cd3c4..211ef376 100644 --- a/patterns/creational/builder.md +++ b/patterns/creational/builder.md @@ -69,7 +69,7 @@ construction has side effects. Separates methods for building from other methods. -Prevents proliferation of constructors +Prevents proliferation of constructors. Can be used for one-liner initialisation as well as more complex construction. @@ -89,8 +89,7 @@ This pattern is often used where the builder object is useful in its own right, rather than being just a builder. For example, see [`std::process::Command`](https://doc.rust-lang.org/std/process/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` pattern -of naming is not used. +(a process). In these cases, the `T` and `TBuilder` naming pattern is not used. The example takes and returns the builder by value. It is often more ergonomic (and more efficient) to take and return the builder as a mutable reference. The From f0e44b59205367bdad8d9db49cfd19374976a1b4 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 17 Aug 2022 03:36:32 +0200 Subject: [PATCH 151/217] Fix #319 (#320) --- idioms/ctor.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/idioms/ctor.md b/idioms/ctor.md index dbb74698..6927bf4d 100644 --- a/idioms/ctor.md +++ b/idioms/ctor.md @@ -88,8 +88,11 @@ impl Second { } ``` -**Note:** When implementing `Default` for a type, it is neither required nor -recommended to also provide an associated function `new` without arguments. +**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. **Hint:** The advantage of implementing or deriving `Default` is that your type can now be used where a `Default` implementation is required, most prominently, @@ -103,6 +106,10 @@ any of the [`*or_default` functions in the standard library][std-or-default]. - The [builder pattern](../patterns/creational/builder.md) for constructing objects where there are multiple configurations. +- [API Guidelines/C-COMMON-TRAITS][API Guidelines/C-COMMON-TRAITS] for + implementing both, `Default` and `new`. + [associated function]: https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions [std-default]: https://doc.rust-lang.org/stable/std/default/trait.Default.html [std-or-default]: https://doc.rust-lang.org/stable/std/?search=or_default +[API Guidelines/C-COMMON-TRAITS]: https://rust-lang.github.io/api-guidelines/interoperability.html#types-eagerly-implement-common-traits-c-common-traits From d75346d5a293c8bf7b9a199bdb0f99c90bb41560 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:53:08 +0200 Subject: [PATCH 152/217] chore: add link to deref trait (#321) --- idioms/deref.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/idioms/deref.md b/idioms/deref.md index 0c1712e4..0f6d9aeb 100644 --- a/idioms/deref.md +++ b/idioms/deref.md @@ -2,7 +2,8 @@ ## Description -Use the `Deref` trait to treat collections like smart pointers, offering owning +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. ## Example @@ -24,19 +25,19 @@ impl Deref for Vec { } ``` -A `Vec` is an owning collection of `T`s, a slice (`&[T]`) is a borrowed +A `Vec` is an owning collection of `T`s, while a slice (`&[T]`) is a borrowed collection of `T`s. Implementing `Deref` for `Vec` allows implicit dereferencing from `&Vec` to `&[T]` and includes the relationship in auto-derefencing searches. Most methods you might expect to be implemented for `Vec`s are instead implemented for slices. -See also `String` and `&str`. +Also `String` and `&str` have a similar relation. ## Motivation Ownership and borrowing are key aspects of the Rust language. Data structures -must account for these semantics properly in order to give a good user -experience. When implementing a data structure which owns its data, offering a +must account for these semantics properly to give a good user +experience. When implementing a data structure that owns its data, offering a borrowed view of that data allows for more flexible APIs. ## Advantages @@ -56,7 +57,7 @@ pattern can get complex (see the `Borrow` and `AsRef` traits, etc.). Smart pointers and collections are analogous: a smart pointer points to a 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 +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 @@ -74,6 +75,5 @@ slicing syntax. The target will be the borrowed view. ## See also -[Deref polymorphism anti-pattern](../anti_patterns/deref.md). - -[Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/trait.Deref.html). +- [Deref polymorphism anti-pattern](../anti_patterns/deref.md). +- [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/trait.Deref.html). From 24fd4e2daa7c4089129359a4c3b9570b51674e87 Mon Sep 17 00:00:00 2001 From: amab8901 <83634595+amab8901@users.noreply.github.com> Date: Sun, 23 Oct 2022 15:35:47 +0200 Subject: [PATCH 153/217] RAII: Grammar correction (#324) --- patterns/behavioural/RAII.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/behavioural/RAII.md b/patterns/behavioural/RAII.md index f27e6f02..4b3f4409 100644 --- a/patterns/behavioural/RAII.md +++ b/patterns/behavioural/RAII.md @@ -5,7 +5,7 @@ [RAII][wikipedia] 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 an RAII object as a guard of some resource and relying +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. ## Example From 06f79a20db6b4f3ac0a6596de82f68163c75728f Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Mon, 28 Nov 2022 22:45:12 +0100 Subject: [PATCH 154/217] Upgrade to mdbook version v0.4.22 (#328) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 5d502324..182eb7cd 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.21 +MDBOOK_VERSION=0.4.22 From c91ffc78a4bc99a728617648fa78a14e2adfd685 Mon Sep 17 00:00:00 2001 From: jhwgh1968 Date: Sat, 10 Dec 2022 01:23:26 +0000 Subject: [PATCH 155/217] Add Lenses and Prisms (#326) --- SUMMARY.md | 1 + functional/lenses.md | 368 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 functional/lenses.md diff --git a/SUMMARY.md b/SUMMARY.md index aa85661d..90b6b6af 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -48,6 +48,7 @@ - [Functional Programming](./functional/index.md) - [Programming paradigms](./functional/paradigms.md) - [Generics as Type Classes](./functional/generics-type-classes.md) + - [Lenses and Prisms](./functional/lenses.md) - [Additional Resources](./additional_resources/index.md) - [Design principles](./additional_resources/design-principles.md) diff --git a/functional/lenses.md b/functional/lenses.md new file mode 100644 index 00000000..37a81bc2 --- /dev/null +++ b/functional/lenses.md @@ -0,0 +1,368 @@ +# Lenses and Prisms + +This is a pure functional concept that is not frequently used in Rust. +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. + +## Lenses: Uniform Access Across Types + +A lens is a concept from functional progamming languages that allows +accessing parts of a data type in an abstract, unified way.[^1] +In basic concept, it is similar to the way Rust traits work with type erasure, +but it has a bit more power and flexibility. + +For example, suppose a bank contains several JSON formats for customer +data. +This is because they come from different databases or legacy systems. +One database contains the data needed to perform credit checks: + +```json +{ "name": "Jane Doe", + "dob": "2002-02-24", + [...] + "customer_id": 1048576332, +} +``` + +Another one contains the account information: + +```json +{ "customer_id": 1048576332, + "accounts": [ + { "account_id": 2121, + "account_type: "savings", + "joint_customer_ids": [], + [...] + }, + { "account_id": 2122, + "account_type: "checking", + "joint_customer_ids": [1048576333], + [...] + }, + ] +} +``` + +Notice that both types have a customer ID number which corresponds to a person. +How would a single function handle both records of different types? + +In Rust, a `struct` could represent each of these types, and a trait would have +a `get_customer_id` function they would implement: + +```rust +use std::collections::HashSet; + +pub struct Account { + account_id: u32, + account_type: String, + // other fields omitted +} + +pub trait CustomerId { + fn get_customer_id(&self) -> u64; +} + +pub struct CreditRecord { + customer_id: u64, + name: String, + dob: String, + // other fields omitted +} + +impl CustomerId for CreditRecord { + fn get_customer_id(&self) -> u64 { + self.customer_id + } +} + +pub struct AccountRecord { + customer_id: u64, + accounts: Vec, +} + +impl CustomerId for AccountRecord { + fn get_customer_id(&self) -> u64 { + self.customer_id + } +} + +// static polymorphism: only one type, but each function call can choose it +fn unique_ids_set(records: &[R]) -> HashSet { + records.iter().map(|r| r.get_customer_id()).collect() +} + +// dynamic dispatch: iterates over any type with a customer ID, collecting all +// values together +fn unique_ids_iter(iterator: I) -> HashSet + where I: Iterator> +{ + iterator.map(|r| r.as_ref().get_customer_id()).collect() +} +``` + +Lenses, however, allow the code supporting customer ID to be moved from the +*type* to the *accessor function*. +Rather than implementing a trait on each type, all matching structures can +simply be accessed the same way. + +While the Rust language itself does not support this (type erasure is the +preferred solution to this problem), the [lens-rs +crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows code +that feels like this to be written with macros: + +```rust,ignore +use std::collections::HashSet; + +use lens_rs::{optics, Lens, LensRef, Optics}; + +#[derive(Clone, Debug, Lens /* derive to allow lenses to work */)] +pub struct CreditRecord { + #[optic(ref)] // macro attribute to allow viewing this field + customer_id: u64, + name: String, + dob: String, + // other fields omitted +} + +#[derive(Clone, Debug)] +pub struct Account { + account_id: u32, + account_type: String, + // other fields omitted +} + +#[derive(Clone, Debug, Lens)] +pub struct AccountRecord { + #[optic(ref)] + customer_id: u64, + accounts: Vec, +} + +fn unique_ids_lens(iter: impl Iterator) -> HashSet +where + T: LensRef, // any type with this field +{ + iter.map(|r| *r.view_ref(optics!(customer_id))).collect() +} +``` + +The version of `unique_ids_lens` shown here allows any type to be in the iterator, +so long as it has an attribute called `customer_id` which can be accessed by +the function. +This is how most functional programming languages operate on lenses. + +Rather than macros, they achieve this with a technique known as "currying". +That is, they "partially construct" the function, leaving the type of the +final parameter (the value being operated on) unfilled until the function is +called. +Thus it can be called with different types dynamically even from one place in +the code. +That is what the `optics!` and `view_ref` in the example above simulates. + +The functional approach need not be restricted to accessing members. +More powerful lenses can be created which both *set* and *get* data in a +structure. +But the concept really becomes interesting when used as a building block for +composition. +That is where the concept appears more clearly in Rust. + +## Prisms: A Higher-Order form of "Optics" + +A simple function such as `unique_ids_lens` above operates on a single lens. +A *prism* is a function that operates on a *family* of lenses. +It is one conceptual level higher, using lenses as a building block, and +continuing the metaphor, is part of a family of "optics". +It is the main one that is useful in understanding Rust APIs, so will be the +focus here. + +The same way that traits allow "lens-like" design with static polymorphism and +dynamic dispatch, prism-like designs appear in Rust APIs which split problems +into multiple associated types to be composed. +A good example of this is the traits in the parsing crate *Serde*. + +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 some type in any library +which parses a new format: + +```rust,ignore +pub trait Deserializer<'de>: Sized { + type Error: Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>; + + // remainder ommitted +} +``` + +For a trait that is just supposed to parse data from a format and return a +value, this looks odd. + +Why are all the return types type erased? + +To understand that, we need to keep the lens concept in mind and look at +the definition of the `Visitor` type that is passed in generically: + +```rust,ignore +pub trait Visitor<'de>: Sized { + type Value; + + fn visit_bool(self, v: bool) -> Result + where + E: Error; + + fn visit_u64(self, v: u64) -> Result + where + E: Error; + + fn visit_str(self, v: &str) -> Result + where + E: Error; + + // remainder omitted +} +``` + +The job of the `Visitor` type is to construct values in the *Serde* data model, +which are represented by its associated `Value` type. + +These values represent parts of the Rust value being deserialized. +If this fails, it returns an `Error` type - an error type determined by the +`Deserializer` when its methods were called. + +This highlights that `Deserializer` is similar to `CustomerId` from earlier, +allowing any format parser which implements it to create `Value`s based on what +it parsed. +The `Value` trait is acting like a lens in functional programming languages. + +But unlike the `CustomerId` trait, the return types of `Visitor` methods are +*generic*, and the concrete `Value` type is *determined by the Visitor itself*. + +Instead of acting as one lens, it effectively acts as a family of +lenses, one for each concrete type of `Visitor`. + +The `Deserializer` API is based on having a generic set of "lenses" work across +a set of other generic types for "observation". +It is a *prism*. + +For example, consider the identity record from earlier but simplified: + +```json +{ "name": "Jane Doe", + "customer_id": 1048576332, +} +``` + +How would the *Serde* library deserialize this JSON into `struct CreditRecord`? + +1. The user would call a library function to deserialize the data. This would + create a `Deserializer` based on the JSON format. +1. 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: `u64` and `String`. +1. The deserializer would make calls to the `Visitor` as it parsed items. +1. The `Visitor` would indicate if the items found were expected, and if not, + raise an error to indicate deserialization has failed. + +For our very simple structure above, the expected pattern would be: + +1. Visit a map (*Serde*'s equvialent to `HashMap` or JSON's dictionary). +1. Visit a string key called "name". +1. Visit a string value, which will go into the `name` field. +1. Visit a string key called "customer_id". +1. Visit a string value, which will go into the `customer_id` field. +1. Visit the end of the map. + +But what determines which "observation" pattern is expected? + +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. + +*Serde* solves this usability challenge with a derive macro: + +```rust,ignore +use serde::Deserialize; + +#[derive(Deserialize)] +struct IdRecord { + name: String, + customer_id: String, +} +``` + +That macro simply generates an impl block causing the struct to implement a +trait called `Deserialize`. + +It is defined this way: + +```rust,ignore +pub trait Deserialize<'de>: Sized { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; +} +``` + +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. + +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. + +For a complete example, see the [*Serde* +documentation](https://serde.rs/deserialize-struct.html). + +To wrap up, this is the power of *Serde*: + +1. The structure being parsed is represented by an `impl` block for `Deserialize` +1. The input data format (e.g. JSON) is represented by a `Deserializer` called + by `Deserialize` +1. The `Deserializer` acts like a prism which "refracts" lens-like `Visitor` + calls which actually build the data value + +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. + +To emphasize, the only reason this model works on any format and any type is +because the `Deserializer` trait's output type **is specified by the +implementor of `Visitor` it is passed**, rather than being tied to one specific +type. +This was not true in the account example earlier. + +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. + +## See Also + +- [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses + implementation, with a cleaner interface than these examples +- [serde](https://serde.rs) itself, which makes these concepts intuitive for + end users (i.e. defining the structs) without needing to undestand the + details +- [luminance](https://github.com/phaazon/luminance-rs) is a crate for drawing + computer graphics that uses lens API design, including proceducal macros to + create full prisms for buffers of different pixel types that remain generic +- [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. +- [Paper: Profunctor Optics: Modular Data + Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf) + +[^1]: [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) From 662e537971cf203afcb0c3d9045dc00419e4e35c Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 22 Dec 2022 15:56:56 +0100 Subject: [PATCH 156/217] chore: update to mdbook v0.4.25 (#331) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 182eb7cd..cc864460 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.22 +MDBOOK_VERSION=0.4.25 From ab81da9b208ce97586c09078726d8245ae0fad02 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 22 Dec 2022 15:59:00 +0100 Subject: [PATCH 157/217] Add edit url (#333) --- book.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/book.toml b/book.toml index c43d6724..c397f6df 100644 --- a/book.toml +++ b/book.toml @@ -16,5 +16,6 @@ edition = "2018" default-theme = "rust" git-repository-url = "https://github.com/rust-unofficial/patterns" git-repository-icon = "fa-github" +edit-url-template = "https://github.com/rust-unofficial/patterns/edit/main/{path}" # [output.linkcheck] # enable the "mdbook-linkcheck" renderer, disabled due to gh-actions From 0d6ccfc62b3dcf6bcc51c739d639e5cca5a06602 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Fri, 23 Dec 2022 14:02:14 +0100 Subject: [PATCH 158/217] add site url (#334) --- book.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/book.toml b/book.toml index c397f6df..f87401c6 100644 --- a/book.toml +++ b/book.toml @@ -14,6 +14,7 @@ edition = "2018" [output.html] default-theme = "rust" +site-url = "/patterns/" git-repository-url = "https://github.com/rust-unofficial/patterns" git-repository-icon = "fa-github" edit-url-template = "https://github.com/rust-unofficial/patterns/edit/main/{path}" From be0f1b1db0af45c01fdf152de1ed26dba0014ba1 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 18 Jan 2023 18:39:50 +0100 Subject: [PATCH 159/217] Replace wording "abuse" with "misuse" (#339) The wording is imho pretty clear connotated with sexual abuse and every time I read it I feel like it's misplaced. So I feel like replacing "abuse" with "misuse" is a better and clear wording. --- anti_patterns/deref.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anti_patterns/deref.md b/anti_patterns/deref.md index c6c65426..b6f8f789 100644 --- a/anti_patterns/deref.md +++ b/anti_patterns/deref.md @@ -2,7 +2,7 @@ ## Description -Abuse the `Deref` trait to emulate inheritance between structs, and thus reuse +Misuse the `Deref` trait to emulate inheritance between structs, and thus reuse methods. ## Example @@ -81,7 +81,7 @@ impl Bar { ## Disadvantages Most importantly this is a surprising idiom - future programmers reading this in -code will not expect this to happen. That's because we are abusing the `Deref` +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. From 7580985e8ba4bb03f488a8f29c47fb8ef3f64e99 Mon Sep 17 00:00:00 2001 From: Taras Burko Date: Thu, 9 Feb 2023 21:14:26 +0000 Subject: [PATCH 160/217] Fix JSON formatter bug in Strategy pattern (#340) Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- patterns/behavioural/strategy.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/patterns/behavioural/strategy.md b/patterns/behavioural/strategy.md index a5aac8d0..751178b3 100644 --- a/patterns/behavioural/strategy.md +++ b/patterns/behavioural/strategy.md @@ -73,7 +73,9 @@ impl Formatter for Json { buf.push_str(&entry); buf.push(','); } - buf.pop(); // remove extra , at the end + if !data.is_empty() { + buf.pop(); // remove extra , at the end + } buf.push(']'); } } From 87373fa34d1f814abf22379c93820ab09e426fba Mon Sep 17 00:00:00 2001 From: Mikhail Trishchenkov Date: Sat, 11 Feb 2023 23:21:54 +0700 Subject: [PATCH 161/217] New idiom: return moved arg on error (#336) Co-authored-by: Julian Ganz Co-authored-by: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> --- SUMMARY.md | 1 + idioms/return-consumed-arg-on-error.md | 61 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 idioms/return-consumed-arg-on-error.md diff --git a/SUMMARY.md b/SUMMARY.md index 90b6b6af..2c73804f 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -20,6 +20,7 @@ - [Privacy For Extensibility](./idioms/priv-extend.md) - [Easy doc initialization](./idioms/rustdoc-init.md) - [Temporary mutability](./idioms/temporary-mutability.md) + - [Return consumed arg on error](./idioms/return-consumed-arg-on-error.md) - [Design Patterns](./patterns/index.md) - [Behavioural](./patterns/behavioural/intro.md) diff --git a/idioms/return-consumed-arg-on-error.md b/idioms/return-consumed-arg-on-error.md new file mode 100644 index 00000000..6e65800c --- /dev/null +++ b/idioms/return-consumed-arg-on-error.md @@ -0,0 +1,61 @@ +# Return consumed argument on error + +## Description + +If a fallible function consumes (moves) an argument, return that argument back inside +an error. + +## Example + +```rust +pub fn send(value: String) -> Result<(), SendError> { + println!("using {value} in a meaningful way"); + // Simulate non-deterministic fallible action. + use std::time::SystemTime; + let period = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + if period.subsec_nanos() % 2 == 1 { + Ok(()) + } else { + Err(SendError(value)) + } +} + +pub struct SendError(String); + +fn main() { + let mut value = "imagine this is very long string".to_string(); + + let success = 'send: { + // Try to send value two times. + for _ in 0..2 { + value = match send(value) { + Ok(()) => break 'send true, + Err(SendError(value)) => value, + } + } + false + }; + + println!("success: {}", success); +} +``` + +## Motivation + +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. + +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. + +## Advantages + +Better performance because of moving arguments whenever possible. + +## Disadvantages + +Slightly more complex error types. From 8949bcd43388333a9faf037f95dc9e80141088b4 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 12 Feb 2023 23:40:36 +0100 Subject: [PATCH 162/217] Rename loop label (#342) --- idioms/return-consumed-arg-on-error.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/idioms/return-consumed-arg-on-error.md b/idioms/return-consumed-arg-on-error.md index 6e65800c..6a0c471f 100644 --- a/idioms/return-consumed-arg-on-error.md +++ b/idioms/return-consumed-arg-on-error.md @@ -25,17 +25,17 @@ pub struct SendError(String); fn main() { let mut value = "imagine this is very long string".to_string(); - let success = 'send: { + let success = 's: { // Try to send value two times. for _ in 0..2 { value = match send(value) { - Ok(()) => break 'send true, + Ok(()) => break 's true, Err(SendError(value)) => value, } } false }; - + println!("success: {}", success); } ``` From 1d39d25d8c6a050c9c359cbcb3948fac9984bb73 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 5 Mar 2023 17:59:01 +0100 Subject: [PATCH 163/217] Update mdbook version (#348) --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index cc864460..a61fb32d 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -MDBOOK_VERSION=0.4.25 +MDBOOK_VERSION=0.4.28 From f5f8078f46951d16e948df040335188cbce4013e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Sun, 26 Mar 2023 02:41:33 -0700 Subject: [PATCH 164/217] Fix typo in lenses.md (#350) --- functional/lenses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functional/lenses.md b/functional/lenses.md index 37a81bc2..c5f1ab59 100644 --- a/functional/lenses.md +++ b/functional/lenses.md @@ -7,7 +7,7 @@ They also have niche use cases. ## Lenses: Uniform Access Across Types -A lens is a concept from functional progamming languages that allows +A lens is a concept from functional programming languages that allows accessing parts of a data type in an abstract, unified way.[^1] In basic concept, it is similar to the way Rust traits work with type erasure, but it has a bit more power and flexibility. From c30a6eb23675e28bf2c2ff1cc00c160b9cbaac64 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 7 Apr 2023 22:17:42 +0200 Subject: [PATCH 165/217] Refactor repository structure to include translations (#352) --- .env | 1 + .github/workflows/build.yml | 119 + .github/workflows/ci.yml | 53 - .github/workflows/gh-pages.yml | 31 - .github/workflows/install-mdbook/action.yml | 29 + .github/workflows/lint.yml | 14 + .github/workflows/publish.yml | 67 + .github/workflows/setup-rust-cache/action.yml | 11 + CONTRIBUTING.md | 2 +- book.toml | 16 +- dprint.json | 11 + language-picker.css | 8 + patterns/structural/unsafe-mods.md | 34 - po/messages.pot | 7255 +++++++++++++++++ SUMMARY.md => src/SUMMARY.md | 6 +- .../design-principles.md | 0 .../additional_resources}/index.md | 0 .../anti_patterns}/borrow_clone.md | 0 .../anti_patterns}/deny-warnings.md | 4 +- {anti_patterns => src/anti_patterns}/deref.md | 0 {anti_patterns => src/anti_patterns}/index.md | 0 .../functional}/generics-type-classes.md | 60 +- {functional => src/functional}/index.md | 2 +- {functional => src/functional}/lenses.md | 33 +- {functional => src/functional}/paradigms.md | 52 +- {idioms => src/idioms}/coercion-arguments.md | 4 +- {idioms => src/idioms}/concat-format.md | 0 {idioms => src/idioms}/ctor.md | 14 +- {idioms => src/idioms}/default.md | 4 +- {idioms => src/idioms}/deref.md | 0 {idioms => src/idioms}/dtor-finally.md | 0 .../idioms}/ffi/accepting-strings.md | 10 +- {idioms => src/idioms}/ffi/errors.md | 2 +- {idioms => src/idioms}/ffi/intro.md | 2 +- {idioms => src/idioms}/ffi/passing-strings.md | 4 +- {idioms => src/idioms}/index.md | 0 {idioms => src/idioms}/mem-replace.md | 12 +- .../idioms}/on-stack-dyn-dispatch.md | 23 +- {idioms => src/idioms}/option-iter.md | 12 +- {idioms => src/idioms}/pass-var-to-closure.md | 0 {idioms => src/idioms}/priv-extend.md | 0 .../idioms}/return-consumed-arg-on-error.md | 0 {idioms => src/idioms}/rustdoc-init.md | 8 +- .../idioms}/temporary-mutability.md | 0 intro.md => src/intro.md | 0 .../patterns}/behavioural/RAII.md | 0 .../patterns}/behavioural/command.md | 0 .../patterns}/behavioural/interpreter.md | 5 +- .../patterns}/behavioural/intro.md | 0 .../patterns}/behavioural/newtype.md | 6 +- .../patterns}/behavioural/strategy.md | 1 - .../patterns}/behavioural/visitor.md | 0 .../patterns}/creational/builder.md | 0 {patterns => src/patterns}/creational/fold.md | 0 .../patterns}/creational/intro.md | 0 {patterns => src/patterns}/ffi/export.md | 28 +- {patterns => src/patterns}/ffi/intro.md | 4 +- {patterns => src/patterns}/ffi/wrappers.md | 20 +- {patterns => src/patterns}/index.md | 0 .../patterns}/structural/compose-structs.md | 0 .../patterns}/structural/intro.md | 0 .../patterns}/structural/small-crates.md | 14 +- src/patterns/structural/unsafe-mods.md | 34 + {refactoring => src/refactoring}/index.md | 0 src/translations.md | 11 + theme/book.js | 1 + theme/index.hbs | 365 + third_party/mdbook/LICENSE | 362 + third_party/mdbook/README.md | 8 + third_party/mdbook/book.js | 715 ++ translations.md | 6 - 71 files changed, 9184 insertions(+), 299 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/gh-pages.yml create mode 100644 .github/workflows/install-mdbook/action.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/setup-rust-cache/action.yml create mode 100644 dprint.json create mode 100644 language-picker.css delete mode 100644 patterns/structural/unsafe-mods.md create mode 100644 po/messages.pot rename SUMMARY.md => src/SUMMARY.md (93%) rename {additional_resources => src/additional_resources}/design-principles.md (100%) rename {additional_resources => src/additional_resources}/index.md (100%) rename {anti_patterns => src/anti_patterns}/borrow_clone.md (100%) rename {anti_patterns => src/anti_patterns}/deny-warnings.md (97%) rename {anti_patterns => src/anti_patterns}/deref.md (100%) rename {anti_patterns => src/anti_patterns}/index.md (100%) rename {functional => src/functional}/generics-type-classes.md (79%) rename {functional => src/functional}/index.md (87%) rename {functional => src/functional}/lenses.md (91%) rename {functional => src/functional}/paradigms.md (65%) rename {idioms => src/idioms}/coercion-arguments.md (97%) rename {idioms => src/idioms}/concat-format.md (100%) rename {idioms => src/idioms}/ctor.md (95%) rename {idioms => src/idioms}/default.md (95%) rename {idioms => src/idioms}/deref.md (100%) rename {idioms => src/idioms}/dtor-finally.md (100%) rename {idioms => src/idioms}/ffi/accepting-strings.md (95%) rename {idioms => src/idioms}/ffi/errors.md (99%) rename {idioms => src/idioms}/ffi/intro.md (89%) rename {idioms => src/idioms}/ffi/passing-strings.md (96%) rename {idioms => src/idioms}/index.md (100%) rename {idioms => src/idioms}/mem-replace.md (90%) rename {idioms => src/idioms}/on-stack-dyn-dispatch.md (76%) rename {idioms => src/idioms}/option-iter.md (82%) rename {idioms => src/idioms}/pass-var-to-closure.md (100%) rename {idioms => src/idioms}/priv-extend.md (100%) rename {idioms => src/idioms}/return-consumed-arg-on-error.md (100%) rename {idioms => src/idioms}/rustdoc-init.md (98%) rename {idioms => src/idioms}/temporary-mutability.md (100%) rename intro.md => src/intro.md (100%) rename {patterns => src/patterns}/behavioural/RAII.md (100%) rename {patterns => src/patterns}/behavioural/command.md (100%) rename {patterns => src/patterns}/behavioural/interpreter.md (95%) rename {patterns => src/patterns}/behavioural/intro.md (100%) rename {patterns => src/patterns}/behavioural/newtype.md (95%) rename {patterns => src/patterns}/behavioural/strategy.md (99%) rename {patterns => src/patterns}/behavioural/visitor.md (100%) rename {patterns => src/patterns}/creational/builder.md (100%) rename {patterns => src/patterns}/creational/fold.md (100%) rename {patterns => src/patterns}/creational/intro.md (100%) rename {patterns => src/patterns}/ffi/export.md (94%) rename {patterns => src/patterns}/ffi/intro.md (81%) rename {patterns => src/patterns}/ffi/wrappers.md (89%) rename {patterns => src/patterns}/index.md (100%) rename {patterns => src/patterns}/structural/compose-structs.md (100%) rename {patterns => src/patterns}/structural/intro.md (100%) rename {patterns => src/patterns}/structural/small-crates.md (79%) create mode 100644 src/patterns/structural/unsafe-mods.md rename {refactoring => src/refactoring}/index.md (100%) create mode 100644 src/translations.md create mode 100644 theme/book.js create mode 100644 theme/index.hbs create mode 100644 third_party/mdbook/LICENSE create mode 100644 third_party/mdbook/README.md create mode 100644 third_party/mdbook/book.js delete mode 100644 translations.md diff --git a/.env b/.env index a61fb32d..4dae58c1 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ MDBOOK_VERSION=0.4.28 +MDBOOK_I8N_HELPERS_VERSION=0.1.0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..8ae13022 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,119 @@ +name: Test mdbook chapters + +on: + pull_request: + push: + branches: + - main + +env: + CARGO_TERM_COLOR: always + +jobs: + mdbook-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Rust cache + uses: ./.github/workflows/setup-rust-cache + + - name: Install mdbook + uses: ./.github/workflows/install-mdbook + + - name: Test code snippets + run: mdbook test + + # TODO: Activate when first translation is available + # i18n-helpers: + # runs-on: ubuntu-latest + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + + # - name: Install Gettext + # run: sudo apt install gettext + + # - name: Setup Rust cache + # uses: ./.github/workflows/setup-rust-cache + + # - name: Install mdbook + # uses: ./.github/workflows/install-mdbook + + # - name: Generate po/messages.pot + # run: mdbook build -d po + # env: + # MDBOOK_OUTPUT: '{"xgettext": {"pot-file": "messages.pot"}}' + + # - name: Test messages.pot + # run: msgfmt --statistics -o /dev/null po/messages.pot + + # - name: Expand includes without translation + # run: mdbook build -d expanded + # env: + # MDBOOK_OUTPUT: '{"markdown": {}}' + + # - name: Expand includes with no-op translation + # run: mdbook build -d no-op + # env: + # MDBOOK_OUTPUT: '{"markdown": {}}' + # MDBOOK_PREPROCESSOR__GETTEXT__PO_FILE: po/messages.pot + + # - name: Compare no translation to no-op translation + # run: diff --color=always --unified --recursive expanded no-op + + # find-translations: + # runs-on: ubuntu-latest + # outputs: + # languages: ${{ steps.find-translations.outputs.languages }} + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + + # - name: Find translations + # id: find-translations + # shell: python + # run: | + # import os, json, pathlib + # languages = [p.stem for p in pathlib.Path("po").iterdir() if p.suffix == ".po"] + # github_output = open(os.environ["GITHUB_OUTPUT"], "a") + # github_output.write("languages=") + # json.dump(sorted(languages), github_output) + + # translations: + # runs-on: ubuntu-latest + # needs: + # - find-translations + # strategy: + # matrix: + # language: ${{ fromJSON(needs.find-translations.outputs.languages) }} + # env: + # MDBOOK_BOOK__LANGUAGE: ${{ matrix.language }} + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + + # - name: Install Gettext + # run: sudo apt install gettext + + # - name: Setup Rust cache + # uses: ./.github/workflows/setup-rust-cache + + # - name: Install mdbook + # uses: ./.github/workflows/install-mdbook + + # - name: Test ${{ matrix.language }} translation + # run: msgfmt --statistics -o /dev/null po/${{ matrix.language }}.po + + # - name: Build book with ${{ matrix.language }} translation + # run: mdbook build + + # - name: Upload ${{ matrix.language }} translation + # uses: actions/upload-artifact@v3 + # with: + # name: rust-design-patterns-${{ matrix.language }} + # path: book/ + + # - name: Test code snippets with ${{ matrix.language }} translation + # run: mdbook test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index b46c7637..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Continuous Integration - -on: - push: - branches: [main] - pull_request: - -jobs: - deploy-test: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - - name: Read .env - id: mdbook-version - run: | - . ./.env - echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" - - - name: Setup mdBook - uses: peaceiris/actions-mdbook@v1 - with: - mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - - - run: mdbook build - - doc-test: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - - name: Read .env - id: mdbook-version - run: | - . ./.env - echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" - - - name: Setup mdBook - uses: peaceiris/actions-mdbook@v1 - with: - mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - - - run: mdbook test - - markdown-lint: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - name: Lint all files recursively - uses: avto-dev/markdown-lint@v1 - with: - config: '.markdownlint.yaml' - args: '**/*.md' diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml deleted file mode 100644 index 78d1edb2..00000000 --- a/.github/workflows/gh-pages.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: github pages - -on: - push: - branches: - - main - -jobs: - deploy: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - - name: Read .env - id: mdbook-version - run: | - . ./.env - echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" - - - name: Setup mdbook - uses: peaceiris/actions-mdbook@v1 - with: - mdbook-version: '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - - - run: mdbook build - - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./book diff --git a/.github/workflows/install-mdbook/action.yml b/.github/workflows/install-mdbook/action.yml new file mode 100644 index 00000000..51a86b1a --- /dev/null +++ b/.github/workflows/install-mdbook/action.yml @@ -0,0 +1,29 @@ +name: Install mdbook and dependencies + +description: Install the mdbook with the dependencies we need. + +runs: + using: composite + steps: + - name: Read mdbook version from .env + id: mdbook-version + run: | + . ./.env + echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" + shell: bash + + - name: Read mdbook-i8n-helpers version from .env + id: mdbook-i8n-helpers-version + run: | + . ./.env + echo "::set-output name=MDBOOK_I8N_HELPERS_VERSION::${MDBOOK_I8N_HELPERS_VERSION}" + shell: bash + + # The --locked flag is important for reproducible builds. + - name: Install mdbook + run: cargo install mdbook --locked --version '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' + shell: bash + + - name: Install i18n-helpers + run: cargo install mdbook-i18n-helpers --locked --version '${{ steps.mdbook-i8n-helpers-version.outputs.MDBOOK_I8N_HELPERS_VERSION }}' + shell: bash diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..236691e5 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,14 @@ +name: Lint Markdown + +on: + push: + branches: [main] + pull_request: + +jobs: + style: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: dprint/check@v2.2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..ff333c3d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,67 @@ +name: Deploy mdBook sites to GH Pages + +on: + push: + branches: ["main"] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + # TODO: Update the language picker in index.hbs to link new languages. + # TODO: As long as https://github.com/google/mdbook-i18n-helpers/issues/12 is not implemented, yet. + # TODO: Activate when first translation is available + # These are the languages in addition to 'en', which is the main language + # LANGUAGES: xx + +jobs: + publish: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Rust cache + uses: ./.github/workflows/setup-rust-cache + + - name: Install mdbook + uses: ./.github/workflows/install-mdbook + + - name: Build course in English + run: mdbook build -d book + + # TODO: Activate when first translation is available + # - name: Build all translations + # run: | + # for po_lang in ${{ env.LANGUAGES }}; do + # echo "::group::Building $po_lang translation" + # MDBOOK_BOOK__LANGUAGE=$po_lang \ + # MDBOOK_OUTPUT__HTML__SITE_URL=/patterns/$po_lang/ \ + # mdbook build -d book/$po_lang + # echo "::endgroup::" + # done + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: ./book + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.github/workflows/setup-rust-cache/action.yml b/.github/workflows/setup-rust-cache/action.yml new file mode 100644 index 00000000..5a9de192 --- /dev/null +++ b/.github/workflows/setup-rust-cache/action.yml @@ -0,0 +1,11 @@ +name: Setup Rust cache + +description: Configure the rust-cache workflow. + +runs: + using: composite + steps: + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + prefix-key: v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41383c59..85c61b47 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ idioms and other explanations. It is a compilation of collective (sometimes implicit) knowledge as well as experiences that have emerged through collaborative work. -The patterns described here are __not rules__, but should be taken as +The patterns described here are **not rules**, but should be taken as guidelines for writing idiomatic code in Rust. We are collecting Rust patterns in this book so people can learn the tradeoffs between Rust idioms and use them properly in their own code. diff --git a/book.toml b/book.toml index f87401c6..9154a482 100644 --- a/book.toml +++ b/book.toml @@ -4,19 +4,33 @@ authors = ["the rust-unofficial authors"] description = "A catalogue of Rust design patterns, anti-patterns and idioms" language = "en" multilingual = false -src = "." +src = "src" [build] create-missing = false +extra-watch-dirs = ["po", "third_party"] + +[preprocessor.gettext] +after = ["links"] [rust] edition = "2018" [output.html] +curly-quotes = true default-theme = "rust" site-url = "/patterns/" git-repository-url = "https://github.com/rust-unofficial/patterns" git-repository-icon = "fa-github" edit-url-template = "https://github.com/rust-unofficial/patterns/edit/main/{path}" +additional-css = ["./language-picker.css"] +additional-js = ["./third_party/mdbook/book.js"] + +[output.html.fold] +enable = true +level = 1 + +[output.html.playground] +editable = false # [output.linkcheck] # enable the "mdbook-linkcheck" renderer, disabled due to gh-actions diff --git a/dprint.json b/dprint.json new file mode 100644 index 00000000..66ee5b52 --- /dev/null +++ b/dprint.json @@ -0,0 +1,11 @@ +{ + "lineWidth": 80, + "markdown": {}, + "includes": [ + "**/*.{md}" + ], + "excludes": [], + "plugins": [ + "https://plugins.dprint.dev/markdown-0.15.2.wasm" + ] +} \ No newline at end of file diff --git a/language-picker.css b/language-picker.css new file mode 100644 index 00000000..1f7d5377 --- /dev/null +++ b/language-picker.css @@ -0,0 +1,8 @@ +#language-list { + left: auto; + right: 10px; +} + +#language-list a { + color: inherit; +} diff --git a/patterns/structural/unsafe-mods.md b/patterns/structural/unsafe-mods.md deleted file mode 100644 index 41737023..00000000 --- a/patterns/structural/unsafe-mods.md +++ /dev/null @@ -1,34 +0,0 @@ -# Contain unsafety in small modules - -## Description - -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. - -## Advantages - -* This restricts the unsafe code that must be audited -* Writing the outer module is much easier, since you can count on the guarantees -of the inner module - -## Disadvantages - -* Sometimes, it may be hard to find a suitable interface. -* The abstraction may introduce inefficiencies. - -## Examples - -* The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations - in submodules, presenting a safe interface to users. -* `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. - -## See also - -* [Ralf Jung's Blog about invariants in unsafe code](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html) diff --git a/po/messages.pot b/po/messages.pot new file mode 100644 index 00000000..646d9345 --- /dev/null +++ b/po/messages.pot @@ -0,0 +1,7255 @@ + +msgid "" +msgstr "" +"Project-Id-Version: Rust Design Patterns\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en\n" +"Plural-Forms: nplurals=1; plural=0;\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 "" + +#: src\SUMMARY.md:8 +msgid "Constructor" +msgstr "" + +#: src\SUMMARY.md:9 +msgid "The Default Trait" +msgstr "" + +#: 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 "" + +#: src\SUMMARY.md:13 +msgid "On-Stack Dynamic Dispatch" +msgstr "" + +#: src\SUMMARY.md:14 +#: src\SUMMARY.md:40 +msgid "Foreign function interface (FFI)" +msgstr "" + +#: src\SUMMARY.md:15 +msgid "Idiomatic Errors" +msgstr "" + +#: 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 "" + +#: 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 "" + +#: 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 "" + diff --git a/SUMMARY.md b/src/SUMMARY.md similarity index 93% rename from SUMMARY.md rename to src/SUMMARY.md index 2c73804f..c2771940 100644 --- a/SUMMARY.md +++ b/src/SUMMARY.md @@ -4,9 +4,9 @@ - [Translations](./translations.md) - [Idioms](./idioms/index.md) - [Use borrowed types for arguments](./idioms/coercion-arguments.md) - - [Concatenating Strings with `format!`](./idioms/concat-format.md) + - [Concatenating Strings with format!](./idioms/concat-format.md) - [Constructor](./idioms/ctor.md) - - [The `Default` Trait](./idioms/default.md) + - [The Default Trait](./idioms/default.md) - [Collections Are Smart Pointers](./idioms/deref.md) - [Finalisation in Destructors](./idioms/dtor-finally.md) - [`mem::{take(_), replace(_)}`](./idioms/mem-replace.md) @@ -15,7 +15,7 @@ - [Idiomatic Errors](./idioms/ffi/errors.md) - [Accepting Strings](./idioms/ffi/accepting-strings.md) - [Passing Strings](./idioms/ffi/passing-strings.md) - - [Iterating over an `Option`](./idioms/option-iter.md) + - [Iterating over an Option](./idioms/option-iter.md) - [Pass Variables to Closure](./idioms/pass-var-to-closure.md) - [Privacy For Extensibility](./idioms/priv-extend.md) - [Easy doc initialization](./idioms/rustdoc-init.md) diff --git a/additional_resources/design-principles.md b/src/additional_resources/design-principles.md similarity index 100% rename from additional_resources/design-principles.md rename to src/additional_resources/design-principles.md diff --git a/additional_resources/index.md b/src/additional_resources/index.md similarity index 100% rename from additional_resources/index.md rename to src/additional_resources/index.md diff --git a/anti_patterns/borrow_clone.md b/src/anti_patterns/borrow_clone.md similarity index 100% rename from anti_patterns/borrow_clone.md rename to src/anti_patterns/borrow_clone.md diff --git a/anti_patterns/deny-warnings.md b/src/anti_patterns/deny-warnings.md similarity index 97% rename from anti_patterns/deny-warnings.md rename to src/anti_patterns/deny-warnings.md index 1dae9d29..ec4bbda0 100644 --- a/anti_patterns/deny-warnings.md +++ b/src/anti_patterns/deny-warnings.md @@ -47,7 +47,7 @@ explicitly. The following command line will build with all warnings set to `deny`: -```RUSTFLAGS="-D warnings" cargo build``` +`RUSTFLAGS="-D warnings" cargo build` 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) @@ -98,7 +98,7 @@ certain that there will be more deprecated APIs in the future. - [A collection of all clippy lints](https://rust-lang.github.io/rust-clippy/master) - [deprecate attribute] documentation - Type `rustc -W help` for a list of lints on your system. Also type -`rustc --help` for a general list of options + `rustc --help` for a general list of options - [rust-clippy] is a collection of lints for better Rust code [rust-clippy]: https://github.com/Manishearth/rust-clippy diff --git a/anti_patterns/deref.md b/src/anti_patterns/deref.md similarity index 100% rename from anti_patterns/deref.md rename to src/anti_patterns/deref.md diff --git a/anti_patterns/index.md b/src/anti_patterns/index.md similarity index 100% rename from anti_patterns/index.md rename to src/anti_patterns/index.md diff --git a/functional/generics-type-classes.md b/src/functional/generics-type-classes.md similarity index 79% rename from functional/generics-type-classes.md rename to src/functional/generics-type-classes.md index df80a08b..5048ca77 100644 --- a/functional/generics-type-classes.md +++ b/src/functional/generics-type-classes.md @@ -11,17 +11,17 @@ of Rust's compile time guarantees. 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 +same boilerplate code for a `vector` type (known as a `template`) with two different types filled in. 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 +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. This is called **monomorphization**, where different types are created from -**polymorphic** code. This special behavior requires `impl` blocks to specify +**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. @@ -48,11 +48,10 @@ and security controls for the actual files. 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 +and a file name to retrieve. A straightforward implementation would look something like this: ```rust,ignore - enum AuthInfo { Nfs(crate::nfs::AuthInfo), Bootp(crate::bootp::AuthInfo), @@ -65,7 +64,7 @@ struct FileDownloadRequest { ``` This design might work well enough. But now suppose you needed to support -adding metadata that was *protocol specific*. For example, with NFS, you +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. @@ -102,7 +101,7 @@ 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. -In Rust, this is actually possible! The solution is to *add a generic type* in +In Rust, this is actually possible! The solution is to _add a generic type_ in order to split the API. Here is what that looks like: @@ -227,60 +226,53 @@ improve in the future. ## Alternatives -* If a type seems to need a "split API" due to construction or partial -initialization, consider the -[Builder Pattern](../patterns/creational/builder.md) instead. +- If a type seems to need a "split API" due to construction or partial + initialization, consider the + [Builder Pattern](../patterns/creational/builder.md) instead. -* If the API between types does not change -- only the behavior does -- then -the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used -instead. +- If the API between types does not change -- only the behavior does -- then + the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used + instead. ## See also This pattern is used throughout the standard library: -* `Vec` can be cast from a String, unlike every other type of `Vec`.[^1] -* They can also be cast into a binary heap, but only if they contain a type +- `Vec` can be cast from a String, unlike every other type of `Vec`.[^1] +- They can also be cast into a binary heap, but only if they contain a type that implements the `Ord` trait.[^2] -* The `to_string` method was specialized for `Cow` only of type `str`.[^3] +- The `to_string` method was specialized for `Cow` only of type `str`.[^3] It is also used by several popular crates to allow API flexibility: -* The `embedded-hal` ecosystem used for embedded devices makes extensive use of +- 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] -* The `hyper` HTTP client library uses this to expose rich APIs for different +- 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] -* The "type state" pattern -- where an object gains and loses API based on an +- 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] -[^1]: See: [impl From\ for Vec\]( -https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811) +[^1]: See: [impl From\ for Vec\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811) -[^2]: See: [impl\ From\\> for BinaryHeap\]( -https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) +[^2]: See: [impl\ From\\> for BinaryHeap\](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) -[^3]: See: [impl\<'\_\> ToString for Cow\<'\_, str>]( -https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) +[^3]: See: [impl\<'\_\> ToString for Cow\<'\_, str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) [^4]: 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) +[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) [^5]: 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) +[https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html](https://docs.rs/hyper/0.14.5/hyper/client/struct.Client.html) [^6]: 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/) +[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) +[Rusty Typestate Series (an extensive thesis)](https://web.archive.org/web/20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index) diff --git a/functional/index.md b/src/functional/index.md similarity index 87% rename from functional/index.md rename to src/functional/index.md index b29e9caf..8be691f9 100644 --- a/functional/index.md +++ b/src/functional/index.md @@ -3,7 +3,7 @@ Rust is an imperative language, but it follows many [functional programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms. -> In computer science, *functional programming* is a programming paradigm where +> 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 diff --git a/functional/lenses.md b/src/functional/lenses.md similarity index 91% rename from functional/lenses.md rename to src/functional/lenses.md index c5f1ab59..3b160dff 100644 --- a/functional/lenses.md +++ b/src/functional/lenses.md @@ -102,13 +102,12 @@ fn unique_ids_iter(iterator: I) -> HashSet ``` Lenses, however, allow the code supporting customer ID to be moved from the -*type* to the *accessor function*. +_type_ to the _accessor function_. Rather than implementing a trait on each type, all matching structures can simply be accessed the same way. While the Rust language itself does not support this (type erasure is the -preferred solution to this problem), the [lens-rs -crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows code +preferred solution to this problem), the [lens-rs crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows code that feels like this to be written with macros: ```rust,ignore @@ -161,7 +160,7 @@ the code. That is what the `optics!` and `view_ref` in the example above simulates. The functional approach need not be restricted to accessing members. -More powerful lenses can be created which both *set* and *get* data in a +More powerful lenses can be created which both _set_ and _get_ data in a structure. But the concept really becomes interesting when used as a building block for composition. @@ -170,7 +169,7 @@ That is where the concept appears more clearly in Rust. ## Prisms: A Higher-Order form of "Optics" A simple function such as `unique_ids_lens` above operates on a single lens. -A *prism* is a function that operates on a *family* of lenses. +A _prism_ is a function that operates on a _family_ of lenses. It is one conceptual level higher, using lenses as a building block, and continuing the metaphor, is part of a family of "optics". It is the main one that is useful in understanding Rust APIs, so will be the @@ -179,9 +178,9 @@ focus here. The same way that traits allow "lens-like" design with static polymorphism and dynamic dispatch, prism-like designs appear in Rust APIs which split problems into multiple associated types to be composed. -A good example of this is the traits in the parsing crate *Serde*. +A good example of this is the traits in the parsing crate _Serde_. -Trying to understand the way *Serde* works by only reading the API is a +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 some type in any library which parses a new format: @@ -230,7 +229,7 @@ pub trait Visitor<'de>: Sized { } ``` -The job of the `Visitor` type is to construct values in the *Serde* data model, +The job of the `Visitor` type is to construct values in the _Serde_ data model, which are represented by its associated `Value` type. These values represent parts of the Rust value being deserialized. @@ -243,14 +242,14 @@ it parsed. The `Value` trait is acting like a lens in functional programming languages. But unlike the `CustomerId` trait, the return types of `Visitor` methods are -*generic*, and the concrete `Value` type is *determined by the Visitor itself*. +_generic_, and the concrete `Value` type is _determined by the Visitor itself_. Instead of acting as one lens, it effectively acts as a family of lenses, one for each concrete type of `Visitor`. The `Deserializer` API is based on having a generic set of "lenses" work across a set of other generic types for "observation". -It is a *prism*. +It is a _prism_. For example, consider the identity record from earlier but simplified: @@ -260,7 +259,7 @@ For example, consider the identity record from earlier but simplified: } ``` -How would the *Serde* library deserialize this JSON into `struct CreditRecord`? +How would the _Serde_ library deserialize this JSON into `struct CreditRecord`? 1. The user would call a library function to deserialize the data. This would create a `Deserializer` based on the JSON format. @@ -273,7 +272,7 @@ How would the *Serde* library deserialize this JSON into `struct CreditRecord`? For our very simple structure above, the expected pattern would be: -1. Visit a map (*Serde*'s equvialent to `HashMap` or JSON's dictionary). +1. Visit a map (_Serde_'s equvialent to `HashMap` or JSON's dictionary). 1. Visit a string key called "name". 1. Visit a string value, which will go into the `name` field. 1. Visit a string key called "customer_id". @@ -287,7 +286,7 @@ 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. -*Serde* solves this usability challenge with a derive macro: +_Serde_ solves this usability challenge with a derive macro: ```rust,ignore use serde::Deserialize; @@ -323,10 +322,9 @@ The `deserialize` code will then create a `Visitor` which will have its calls If everything goes well, eventually that `Visitor` will construct a value corresponding to the type being parsed and return it. -For a complete example, see the [*Serde* -documentation](https://serde.rs/deserialize-struct.html). +For a complete example, see the [_Serde_ documentation](https://serde.rs/deserialize-struct.html). -To wrap up, this is the power of *Serde*: +To wrap up, this is the power of _Serde_: 1. The structure being parsed is represented by an `impl` block for `Deserialize` 1. The input data format (e.g. JSON) is represented by a `Deserializer` called @@ -359,8 +357,7 @@ But it may also need procedural macros to create bridges for its generics. - [luminance](https://github.com/phaazon/luminance-rs) is a crate for drawing computer graphics that uses lens API design, including proceducal macros to create full prisms for buffers of different pixel types that remain generic -- [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) +- [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. - [Paper: Profunctor Optics: Modular Data Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf) diff --git a/functional/paradigms.md b/src/functional/paradigms.md similarity index 65% rename from functional/paradigms.md rename to src/functional/paradigms.md index 9fc3b99e..099fd785 100644 --- a/functional/paradigms.md +++ b/src/functional/paradigms.md @@ -2,8 +2,8 @@ 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. +describe **how** to do something, whereas declarative programs describe +**what** to do. Let's sum the numbers from 1 to 10 to show this. ## Imperative @@ -22,17 +22,17 @@ Each time through the loop, we add the corresponding value in the range. Then we print it out. | `i` | `sum` | -|:---:|:-----:| -| 1 | 1 | -| 2 | 3 | -| 3 | 6 | -| 4 | 10 | -| 5 | 15 | -| 6 | 21 | -| 7 | 28 | -| 8 | 36 | -| 9 | 45 | -| 10 | 55 | +| :-: | :---: | +| 1 | 1 | +| 2 | 3 | +| 3 | 6 | +| 4 | 10 | +| 5 | 15 | +| 6 | 21 | +| 7 | 28 | +| 8 | 36 | +| 9 | 45 | +| 10 | 55 | This is how most of us start out programming. We learn that a program is a set of steps. @@ -44,8 +44,8 @@ println!("{}", (1..11).fold(0, |a, b| a + b)); ``` 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) +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. Here, we are composing functions of addition (this closure: `|a, b| a + b`) @@ -56,14 +56,14 @@ result. This process continues until we get to the last element in the range, `10`. | `a` | `b` | result | -|:---:|:---:|:------:| -| 0 | 1 | 1 | -| 1 | 2 | 3 | -| 3 | 3 | 6 | -| 6 | 4 | 10 | -| 10 | 5 | 15 | -| 15 | 6 | 21 | -| 21 | 7 | 28 | -| 28 | 8 | 36 | -| 36 | 9 | 45 | -| 45 | 10 | 55 | +| :-: | :-: | :----: | +| 0 | 1 | 1 | +| 1 | 2 | 3 | +| 3 | 3 | 6 | +| 6 | 4 | 10 | +| 10 | 5 | 15 | +| 15 | 6 | 21 | +| 21 | 7 | 28 | +| 28 | 8 | 36 | +| 36 | 9 | 45 | +| 45 | 10 | 55 | diff --git a/idioms/coercion-arguments.md b/src/idioms/coercion-arguments.md similarity index 97% rename from idioms/coercion-arguments.md rename to src/idioms/coercion-arguments.md index 2ca63ab5..e37d63c4 100644 --- a/idioms/coercion-arguments.md +++ b/src/idioms/coercion-arguments.md @@ -7,8 +7,8 @@ when you are deciding which argument type to use for a function argument. In this way, the function will accept more input types. 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__. +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`. Using borrowed types you can avoid layers of indirection for those instances diff --git a/idioms/concat-format.md b/src/idioms/concat-format.md similarity index 100% rename from idioms/concat-format.md rename to src/idioms/concat-format.md diff --git a/idioms/ctor.md b/src/idioms/ctor.md similarity index 95% rename from idioms/ctor.md rename to src/idioms/ctor.md index 6927bf4d..13e0cc6a 100644 --- a/idioms/ctor.md +++ b/src/idioms/ctor.md @@ -3,9 +3,9 @@ ## Description Rust does not have constructors as a language construct. Instead, the -convention is to use an [associated function][] `new` to create an object: +convention is to use an [associated function][associated function] `new` to create an object: -```rust +````rust /// Time in seconds. /// /// # Example @@ -30,13 +30,13 @@ impl Second { self.value } } -``` +```` ## Default Constructors Rust supports default constructors with the [`Default`][std-default] trait: -```rust +````rust /// Time in seconds. /// /// # Example @@ -61,12 +61,12 @@ impl Default for Second { Self { value: 0 } } } -``` +```` `Default` can also be derived if all types of all fields implement `Default`, like they do with `Second`: -```rust +````rust /// Time in seconds. /// /// # Example @@ -86,7 +86,7 @@ impl Second { self.value } } -``` +```` **Note:** It is common and expected for types to implement both `Default` and an empty `new` constructor. `new` is the constructor diff --git a/idioms/default.md b/src/idioms/default.md similarity index 95% rename from idioms/default.md rename to src/idioms/default.md index 1baf58cd..3954b8b9 100644 --- a/idioms/default.md +++ b/src/idioms/default.md @@ -2,7 +2,7 @@ ## Description -Many types in Rust have a [constructor]. However, this is *specific* to the +Many types in Rust have a [constructor]. However, this is _specific_ to the type; Rust cannot abstract over "everything that has a `new()` method". To allow this, the [`Default`] trait was conceived, which can be used with containers and other generic types (e.g. see [`Option::unwrap_or_default()`]). @@ -58,7 +58,7 @@ fn main() { ## See also - The [constructor] idiom is another way to generate instances that may or may -not be "default" + not be "default" - The [`Default`] documentation (scroll down for the list of implementors) - [`Option::unwrap_or_default()`] - [`derive(new)`] diff --git a/idioms/deref.md b/src/idioms/deref.md similarity index 100% rename from idioms/deref.md rename to src/idioms/deref.md diff --git a/idioms/dtor-finally.md b/src/idioms/dtor-finally.md similarity index 100% rename from idioms/dtor-finally.md rename to src/idioms/dtor-finally.md diff --git a/idioms/ffi/accepting-strings.md b/src/idioms/ffi/accepting-strings.md similarity index 95% rename from idioms/ffi/accepting-strings.md rename to src/idioms/ffi/accepting-strings.md index c4b88e60..8e0ca84c 100644 --- a/idioms/ffi/accepting-strings.md +++ b/src/idioms/ffi/accepting-strings.md @@ -71,7 +71,7 @@ The example is is written to ensure that: 1. The `unsafe` block is as small as possible. 2. The pointer with an "untracked" lifetime becomes a "tracked" shared - reference + reference Consider an alternative, where the string is actually copied: @@ -120,15 +120,15 @@ pub mod unsafe_module { This code in inferior to the original in two respects: 1. There is much more `unsafe` code, and more importantly, more invariants it - must uphold. + must uphold. 2. Due to the extensive arithmetic required, there is a bug in this version - that cases Rust `undefined behaviour`. + that cases Rust `undefined behaviour`. The bug here is a simple mistake in pointer arithmetic: the string was copied, all `msg_len` bytes of it. However, the `NUL` terminator at the end was not. -The Vector then had its size *set* to the length of the *zero padded string* -- -rather than *resized* to it, which could have added a zero at the end. +The Vector then had its size _set_ to the length of the _zero padded string_ -- +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`! diff --git a/idioms/ffi/errors.md b/src/idioms/ffi/errors.md similarity index 99% rename from idioms/ffi/errors.md rename to src/idioms/ffi/errors.md index 99fc77f6..f254aea0 100644 --- a/idioms/ffi/errors.md +++ b/src/idioms/ffi/errors.md @@ -11,7 +11,7 @@ in a usable way: 1. Flat Enums should be converted to integers and returned as codes. 2. Structured Enums should be converted to an integer code with a string error - message for detail. + message for detail. 3. Custom Error Types should become "transparent", with a C representation. ## Code Example diff --git a/idioms/ffi/intro.md b/src/idioms/ffi/intro.md similarity index 89% rename from idioms/ffi/intro.md rename to src/idioms/ffi/intro.md index d1f14971..93b4862e 100644 --- a/idioms/ffi/intro.md +++ b/src/idioms/ffi/intro.md @@ -7,7 +7,7 @@ traps for inexperienced users of `unsafe` Rust. This section contains idioms that may be useful when doing FFI. 1. [Idiomatic Errors](./errors.md) - Error handling with integer codes and - sentinel return values (such as `NULL` pointers) + sentinel return values (such as `NULL` pointers) 2. [Accepting Strings](./accepting-strings.md) with minimal unsafe code diff --git a/idioms/ffi/passing-strings.md b/src/idioms/ffi/passing-strings.md similarity index 96% rename from idioms/ffi/passing-strings.md rename to src/idioms/ffi/passing-strings.md index 18de5c83..cd540614 100644 --- a/idioms/ffi/passing-strings.md +++ b/src/idioms/ffi/passing-strings.md @@ -9,7 +9,7 @@ followed: 2. Minimize `unsafe` code during the conversion. 3. If the C code can modify the string data, use `Vec` instead of `CString`. 4. Unless the Foreign Function API requires it, the ownership of the string - should not transfer to the callee. + should not transfer to the callee. ## Motivation @@ -19,7 +19,7 @@ are being sent to a foreign function call from a Rust function. 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. +_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. diff --git a/idioms/index.md b/src/idioms/index.md similarity index 100% rename from idioms/index.md rename to src/idioms/index.md diff --git a/idioms/mem-replace.md b/src/idioms/mem-replace.md similarity index 90% rename from idioms/mem-replace.md rename to src/idioms/mem-replace.md index b1ea07f1..1771f2ad 100644 --- a/idioms/mem-replace.md +++ b/src/idioms/mem-replace.md @@ -63,17 +63,16 @@ its parts to decide what to do next. In the second phase we may conditionally change the value (as in the example above). 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 -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 +_something_ must be there.) We could of course `.clone()` name and put the 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. `mem::take` lets us swap out the value, replacing it with it's default value, and returning the previous value. For `String`, the default value is an 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. +`name` _as an owned value_. We can then wrap this in another enum. -__NOTE:__ `mem::replace` is very similar, but allows us to specify what to +**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())`. @@ -92,8 +91,7 @@ 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. -Furthermore, the type you are taking needs to implement the [`Default` -trait](./default.md). However, if the type you're working with doesn't +Furthermore, the type you are taking needs to implement the [`Default` trait](./default.md). However, if the type you're working with doesn't implement this, you can instead use `mem::replace`. ## Discussion diff --git a/idioms/on-stack-dyn-dispatch.md b/src/idioms/on-stack-dyn-dispatch.md similarity index 76% rename from idioms/on-stack-dyn-dispatch.md rename to src/idioms/on-stack-dyn-dispatch.md index d45f3ca9..5ecb31af 100644 --- a/idioms/on-stack-dyn-dispatch.md +++ b/src/idioms/on-stack-dyn-dispatch.md @@ -68,26 +68,25 @@ let readable: Box = if arg == "-" { ## Discussion Rust newcomers will usually learn that Rust requires all variables to be -initialized *before use*, so it's easy to overlook the fact that *unused* +initialized _before use_, so it's easy to overlook the fact that _unused_ variables may well be uninitialized. Rust works quite hard to ensure that this works out fine and only the initialized values are dropped at the end of their scope. The example meets all the constraints Rust places on us: -* All variables are initialized before using (in this case borrowing) them -* Each variable only holds values of a single type. In our example, `stdin` is -of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut dyn -Read` -* Each borrowed value outlives all the references borrowed from it +- All variables are initialized before using (in this case borrowing) them +- Each variable only holds values of a single type. In our example, `stdin` is + of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut dyn Read` +- Each borrowed value outlives all the references borrowed from it ## See also -* [Finalisation in destructors](dtor-finally.md) and -[RAII guards](../patterns/behavioural/RAII.md) can benefit from tight control over -lifetimes. -* For conditionally filled `Option<&T>`s of (mutable) references, one can -initialize an `Option` directly and use its [`.as_ref()`] method to get an -optional reference. +- [Finalisation in destructors](dtor-finally.md) and + [RAII guards](../patterns/behavioural/RAII.md) can benefit from tight control over + lifetimes. +- For conditionally filled `Option<&T>`s of (mutable) references, one can + initialize an `Option` directly and use its [`.as_ref()`] method to get an + optional reference. [`.as_ref()`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.as_ref diff --git a/idioms/option-iter.md b/src/idioms/option-iter.md similarity index 82% rename from idioms/option-iter.md rename to src/idioms/option-iter.md index a3e8adda..f8ac9f97 100644 --- a/idioms/option-iter.md +++ b/src/idioms/option-iter.md @@ -45,15 +45,15 @@ and in most cases you should prefer the latter. ## See also -* [`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()`. +- [`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()`. -* [`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) +- [`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`. -* The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions +- The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions for converting an `Option` to a zero- or one-element slice. -* [Documentation for `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) +- [Documentation for `Option`](https://doc.rust-lang.org/std/option/enum.Option.html) diff --git a/idioms/pass-var-to-closure.md b/src/idioms/pass-var-to-closure.md similarity index 100% rename from idioms/pass-var-to-closure.md rename to src/idioms/pass-var-to-closure.md diff --git a/idioms/priv-extend.md b/src/idioms/priv-extend.md similarity index 100% rename from idioms/priv-extend.md rename to src/idioms/priv-extend.md diff --git a/idioms/return-consumed-arg-on-error.md b/src/idioms/return-consumed-arg-on-error.md similarity index 100% rename from idioms/return-consumed-arg-on-error.md rename to src/idioms/return-consumed-arg-on-error.md diff --git a/idioms/rustdoc-init.md b/src/idioms/rustdoc-init.md similarity index 98% rename from idioms/rustdoc-init.md rename to src/idioms/rustdoc-init.md index 64c1e5d4..da0291a3 100644 --- a/idioms/rustdoc-init.md +++ b/src/idioms/rustdoc-init.md @@ -13,7 +13,7 @@ methods. Each of these methods should have examples. For example: -```rust,ignore +````rust,ignore struct Connection { name: String, stream: TcpStream, @@ -40,7 +40,7 @@ impl Connection { // ... } } -``` +```` ## Example @@ -48,7 +48,7 @@ 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 them as arguments: -```rust,ignore +````rust,ignore struct Connection { name: String, stream: TcpStream, @@ -68,7 +68,7 @@ impl Connection { // ... } } -``` +```` **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 diff --git a/idioms/temporary-mutability.md b/src/idioms/temporary-mutability.md similarity index 100% rename from idioms/temporary-mutability.md rename to src/idioms/temporary-mutability.md diff --git a/intro.md b/src/intro.md similarity index 100% rename from intro.md rename to src/intro.md diff --git a/patterns/behavioural/RAII.md b/src/patterns/behavioural/RAII.md similarity index 100% rename from patterns/behavioural/RAII.md rename to src/patterns/behavioural/RAII.md diff --git a/patterns/behavioural/command.md b/src/patterns/behavioural/command.md similarity index 100% rename from patterns/behavioural/command.md rename to src/patterns/behavioural/command.md diff --git a/patterns/behavioural/interpreter.md b/src/patterns/behavioural/interpreter.md similarity index 95% rename from patterns/behavioural/interpreter.md rename to src/patterns/behavioural/interpreter.md index 21cf4457..854331ba 100644 --- a/patterns/behavioural/interpreter.md +++ b/src/patterns/behavioural/interpreter.md @@ -39,10 +39,9 @@ exp -> term term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ``` -__NOTE:__ This grammar should be further transformed depending on what we are going +**NOTE:** This grammar should be further transformed depending on what we 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) +details please see [Compilers: Principles,Techniques, and Tools](https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools) (aka Dragon Book). ## Solution diff --git a/patterns/behavioural/intro.md b/src/patterns/behavioural/intro.md similarity index 100% rename from patterns/behavioural/intro.md rename to src/patterns/behavioural/intro.md diff --git a/patterns/behavioural/newtype.md b/src/patterns/behavioural/newtype.md similarity index 95% rename from patterns/behavioural/newtype.md rename to src/patterns/behavioural/newtype.md index 8df944f3..9e9f0195 100644 --- a/patterns/behavioural/newtype.md +++ b/src/patterns/behavioural/newtype.md @@ -7,8 +7,8 @@ not be enough? For example, if we want to create a custom `Display` implementation for `String` due to security considerations (e.g. passwords). -For such cases we could use the `Newtype` pattern to provide __type safety__ -and __encapsulation__. +For such cases we could use the `Newtype` pattern to provide **type safety** +and **encapsulation**. ## Description @@ -77,7 +77,7 @@ field is private, which it is by default). ## Disadvantages The downside of newtypes (especially compared with type aliases), is that there -is no special language support. This means there can be *a lot* of boilerplate. +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. diff --git a/patterns/behavioural/strategy.md b/src/patterns/behavioural/strategy.md similarity index 99% rename from patterns/behavioural/strategy.md rename to src/patterns/behavioural/strategy.md index 751178b3..e6e435c7 100644 --- a/patterns/behavioural/strategy.md +++ b/src/patterns/behavioural/strategy.md @@ -155,7 +155,6 @@ fn main() { assert_eq!(0, Adder::add(0, 0, bool_adder)); assert_eq!(5, Adder::add(1, 3, custom_adder)); } - ``` In fact, Rust already uses this idea for `Options`'s `map` method: diff --git a/patterns/behavioural/visitor.md b/src/patterns/behavioural/visitor.md similarity index 100% rename from patterns/behavioural/visitor.md rename to src/patterns/behavioural/visitor.md diff --git a/patterns/creational/builder.md b/src/patterns/creational/builder.md similarity index 100% rename from patterns/creational/builder.md rename to src/patterns/creational/builder.md diff --git a/patterns/creational/fold.md b/src/patterns/creational/fold.md similarity index 100% rename from patterns/creational/fold.md rename to src/patterns/creational/fold.md diff --git a/patterns/creational/intro.md b/src/patterns/creational/intro.md similarity index 100% rename from patterns/creational/intro.md rename to src/patterns/creational/intro.md diff --git a/patterns/ffi/export.md b/src/patterns/ffi/export.md similarity index 94% rename from patterns/ffi/export.md rename to src/patterns/ffi/export.md index 8b5a4f06..f7d32608 100644 --- a/patterns/ffi/export.md +++ b/src/patterns/ffi/export.md @@ -5,12 +5,12 @@ 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: -1. All Encapsulated types should be *owned* by Rust, *managed* by the user, - and *opaque*. -2. All Transactional data types should be *owned* by the user, and *transparent*. +1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user, + and _opaque_. +2. All Transactional data types should be _owned_ by the user, and _transparent_. 3. All library behavior should be functions acting upon Encapsulated types. 4. All library behavior should be encapsulated into types not based on structure, - but *provenance/lifetime*. + but _provenance/lifetime_. ## Motivation @@ -24,7 +24,7 @@ design in Rust as little as possible. There are three goals with any foreign API 1. Make it easy to use in the target language. 2. Avoid the API dictating internal unsafety on the Rust side as much as possible. 3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small - as possible. + as possible. 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 @@ -69,7 +69,7 @@ library's behavior. 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*. +only gives them _a pointer to one_. 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, @@ -90,8 +90,8 @@ 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`. -As noted earlier, this type is *transparent* to the user. But also, this type is -*owned* by the user. +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? @@ -99,14 +99,14 @@ 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. +`malloc` and `free` -- and then _transfer ownership_ in the Rust sense. 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*. +is to _transfer ownership of everything that is transparent_. ## Advantages @@ -114,10 +114,10 @@ This minimizes the number of memory safety guarantees the user must uphold to a relatively small number: 1. Do not call any function with a pointer not returned by `dbm_open` (invalid - access or corruption). + access or corruption). 2. Do not call any function on a pointer after close (use after free). 3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of memory - at the advertised length. + at the advertised length. In addition, it avoids a lot of pointer provenance issues. To understand why, let us consider an alternative in some depth: key iteration. @@ -205,7 +205,7 @@ end-of-iteration marker: 1. The loop condition sets `l` to zero, and enters the loop because `0 >= 0`. 2. The length is incremented, in this case by zero. 3. The if statement is true, so the database is closed. There should be a break - statement here. + statement here. 4. The loop condition executes again, causing a `next` call on the closed object. The worst part about this bug? @@ -221,7 +221,7 @@ and gave up control of their lifetimes. The C code simply must "play nice". 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 +this risk. The POSIX API for `DBM` did this by _consolidating the ownership_ of the iterator with its parent: ```C diff --git a/patterns/ffi/intro.md b/src/patterns/ffi/intro.md similarity index 81% rename from patterns/ffi/intro.md rename to src/patterns/ffi/intro.md index f65a0d28..a2e300fe 100644 --- a/patterns/ffi/intro.md +++ b/src/patterns/ffi/intro.md @@ -7,7 +7,7 @@ for inexperienced users of unsafe Rust. This section contains design patterns that may be useful when doing FFI. 1. [Object-Based API](./export.md) design that has good memory safety characteristics, - and a clean boundary of what is safe and what is unsafe + and a clean boundary of what is safe and what is unsafe 2. [Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust types - together into an opaque "object" + together into an opaque "object" diff --git a/patterns/ffi/wrappers.md b/src/patterns/ffi/wrappers.md similarity index 89% rename from patterns/ffi/wrappers.md rename to src/patterns/ffi/wrappers.md index 77312596..13393ed5 100644 --- a/patterns/ffi/wrappers.md +++ b/src/patterns/ffi/wrappers.md @@ -31,7 +31,7 @@ That API looks like this: 2. Each call to `next_key` will advance the iterator. 3. Calls to `next_key` if the iterator is at the end will do nothing. 4. As noted above, the iterator is "wrapped into" the collection (unlike the native - Rust API). + Rust API). If the iterator implements `nth()` efficiently, then it is possible to make it ephemeral to each function call: @@ -82,9 +82,9 @@ 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. -Suffice it to say, this is *incredibly* difficult. +Suffice it to say, this is _incredibly_ difficult. -Here is an illustration of just *one* pitfall. +Here is an illustration of just _one_ pitfall. A first version of `MySetWrapper` would look like this: @@ -98,8 +98,8 @@ struct MySetWrapper { ``` 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`*. +it's ugly already. But it gets even worse: _any other operation can cause +Rust `undefined behaviour`_. 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 @@ -136,7 +136,7 @@ pub mod unsafe_module { 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, +_exclusive_ access to the object. If the iterator simply exists, it's not exclusive, so we have `undefined behaviour`! [^1] To avoid this, we must have a way of ensuring that mutable reference really is exclusive. @@ -156,7 +156,7 @@ optimizations that C code cannot attain. Being denied access to certain shortcut is the price Rust programmers need to pay. [^1]: For the C programmers out there scratching their heads, the iterator need - not be read *during* this code 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. +not be read _during_ this code 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. diff --git a/patterns/index.md b/src/patterns/index.md similarity index 100% rename from patterns/index.md rename to src/patterns/index.md diff --git a/patterns/structural/compose-structs.md b/src/patterns/structural/compose-structs.md similarity index 100% rename from patterns/structural/compose-structs.md rename to src/patterns/structural/compose-structs.md diff --git a/patterns/structural/intro.md b/src/patterns/structural/intro.md similarity index 100% rename from patterns/structural/intro.md rename to src/patterns/structural/intro.md diff --git a/patterns/structural/small-crates.md b/src/patterns/structural/small-crates.md similarity index 79% rename from patterns/structural/small-crates.md rename to src/patterns/structural/small-crates.md index 01060e31..250db6b6 100644 --- a/patterns/structural/small-crates.md +++ b/src/patterns/structural/small-crates.md @@ -11,24 +11,24 @@ We should take advantage of this tooling, and use smaller, more fine-grained dep ## Advantages -* Small crates are easier to understand, and encourage more modular code. -* Crates allow for re-using code between projects. +- Small crates are easier to understand, and encourage more modular code. +- 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. -* Since the compilation unit +- 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. ## Disadvantages -* This can lead to "dependency hell", when a project depends on multiple conflicting +- 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`. -* Packages on crates.io are not curated. A crate may be poorly written, have +- Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious. -* Two small crates may be less optimized than one large one, since the compiler +- Two small crates may be less optimized than one large one, since the compiler does not perform link-time optimization (LTO) by default. ## Examples @@ -44,4 +44,4 @@ query the number of CPUs on a machine. ## See also -* [crates.io: The Rust community crate host](https://crates.io/) +- [crates.io: The Rust community crate host](https://crates.io/) diff --git a/src/patterns/structural/unsafe-mods.md b/src/patterns/structural/unsafe-mods.md new file mode 100644 index 00000000..c59463b0 --- /dev/null +++ b/src/patterns/structural/unsafe-mods.md @@ -0,0 +1,34 @@ +# Contain unsafety in small modules + +## Description + +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. + +## Advantages + +- This restricts the unsafe code that must be audited +- Writing the outer module is much easier, since you can count on the guarantees + of the inner module + +## Disadvantages + +- Sometimes, it may be hard to find a suitable interface. +- The abstraction may introduce inefficiencies. + +## Examples + +- The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations + in submodules, presenting a safe interface to users. +- `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. + +## See also + +- [Ralf Jung's Blog about invariants in unsafe code](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html) diff --git a/refactoring/index.md b/src/refactoring/index.md similarity index 100% rename from refactoring/index.md rename to src/refactoring/index.md diff --git a/src/translations.md b/src/translations.md new file mode 100644 index 00000000..8d5697b8 --- /dev/null +++ b/src/translations.md @@ -0,0 +1,11 @@ +# Translations + +We are utilizing [mdbook-i18n-helper](https://github.com/google/mdbook-i18n-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) + +## External translations + +- [简体中文](https://fomalhauthmj.github.io/patterns/) + +If you want to add a translation, please open an issue in the +[main repository](https://github.com/rust-unofficial/patterns). diff --git a/theme/book.js b/theme/book.js new file mode 100644 index 00000000..43fb708d --- /dev/null +++ b/theme/book.js @@ -0,0 +1 @@ +../third_party/mdbook/book.js \ No newline at end of file diff --git a/theme/index.hbs b/theme/index.hbs new file mode 100644 index 00000000..dd83020b --- /dev/null +++ b/theme/index.hbs @@ -0,0 +1,365 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + {{> head}} + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + + + + + + + + + + + + +

+ +
+ +
+ {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
+
+ {{{ content }}} +
+ + +
+
+ + + +
+ + {{#if live_reload_endpoint}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + diff --git a/third_party/mdbook/LICENSE b/third_party/mdbook/LICENSE new file mode 100644 index 00000000..be2cc4df --- /dev/null +++ b/third_party/mdbook/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/third_party/mdbook/README.md b/third_party/mdbook/README.md new file mode 100644 index 00000000..fe7e9a39 --- /dev/null +++ b/third_party/mdbook/README.md @@ -0,0 +1,8 @@ +# mdBook + +This directory contains files copied from mdBook. Please see + for the full project. + +## License + +mdBook is licensed under the Mozilla Public License v2.0 ([LICENSE](LICENSE)). diff --git a/third_party/mdbook/book.js b/third_party/mdbook/book.js new file mode 100644 index 00000000..a3384d98 --- /dev/null +++ b/third_party/mdbook/book.js @@ -0,0 +1,715 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +function isPlaygroundModified(playground) { + let code_block = playground.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue() != editor.originalCode; + } else { + return false; + } +} + +// Global variable, shared between modules +function playground_text(playground, hidden = true) { + let code_block = playground.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else if (hidden) { + return code_block.textContent; + } else { + return code_block.innerText; + } +} + +(function codeSnippets() { + function fetch_with_timeout(url, options, timeout = 15000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playgrounds = Array.from(document.querySelectorAll(".playground")); + if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playground_block, playground_crates); + }); + // add Ctrl-Enter command to execute rust code + editor.commands.addCommand({ + name: "run", + bindKey: { + win: "Ctrl-Enter", + mac: "Ctrl-Enter" + }, + exec: _editor => run_rust_code(playground_block) + }); + } + } + } + + // updates the visibility of play button based on `no_run` class and + // used crates vs ones available on http://play.rust-lang.org + function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } + } + + function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if(classes.contains("edition2018")) { + edition = "2018"; + } else if(classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + const playgroundModified = isPlaygroundModified(code_block); + const startTime = window.performance.now(); + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + const endTime = window.performance.now(); + gtag("event", "playground", { + "modified": playgroundModified, + "error": (response.error == null) ? null : 'compilation_error', + "latency": (endTime - startTime) / 1000, + }); + + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => { + const endTime = window.performance.now(); + gtag("event", "playground", { + "modified": playgroundModified, + "error": error.message, + "latency": (endTime - startTime) / 1000, + }); + result_block.innerText = "Playground Communication: " + error.message + }); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + let code_nodes = Array + .from(document.querySelectorAll('code')) + // Don't highlight `inline code` blocks in headers. + .filter(function (node) {return !node.parentElement.classList.contains("header"); }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + code_nodes + .filter(function (node) {return node.classList.contains("editable"); }) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + code_nodes + .filter(function (node) {return !node.classList.contains("editable"); }) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + code_nodes.forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) { + + var lines = Array.from(block.querySelectorAll('.boring')); + // If no lines were hidden, return + if (!lines.length) { return; } + block.classList.add("hide-boring"); + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + var pre_block = block.parentNode; + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-eye')) { + e.target.classList.remove('fa-eye'); + e.target.classList.add('fa-eye-slash'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.remove('hide-boring'); + } else if (e.target.classList.contains('fa-eye-slash')) { + e.target.classList.remove('fa-eye-slash'); + e.target.classList.add('fa-eye'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.add('hide-boring'); + } + }); + }); + + if (window.playground_copyable) { + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playground')) { + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var clipButton = document.createElement('button'); + clipButton.className = 'fa fa-copy clip-button'; + clipButton.title = 'Copy to clipboard'; + clipButton.setAttribute('aria-label', clipButton.title); + clipButton.innerHTML = ''; + + buttons.insertBefore(clipButton, buttons.firstChild); + } + }); + } + + // Process playground code blocks + Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'fa fa-play play-button'; + runCodeButton.hidden = true; + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + if (window.playground_copyable) { + var copyCodeClipboardButton = document.createElement('button'); + copyCodeClipboardButton.className = 'fa fa-copy clip-button'; + copyCodeClipboardButton.innerHTML = ''; + copyCodeClipboardButton.title = 'Copy to clipboard'; + copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); + + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + } + + let code_block = pre_block.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + var undoChangesButton = document.createElement('button'); + undoChangesButton.className = 'fa fa-history reset-button'; + undoChangesButton.title = 'Undo changes'; + undoChangesButton.setAttribute('aria-label', undoChangesButton.title); + + buttons.insertBefore(undoChangesButton, buttons.firstChild); + + undoChangesButton.addEventListener('click', function () { + let editor = window.ace.edit(code_block); + editor.setValue(editor.originalCode); + editor.clearSelection(); + }); + } + }); +})(); + +(function themes() { + var html = document.querySelector('html'); + var themeToggleButton = document.getElementById('theme-toggle'); + var themePopup = document.getElementById('theme-list'); + var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); + var stylesheets = { + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), + }; + + function showThemes() { + themePopup.style.display = 'block'; + themeToggleButton.setAttribute('aria-expanded', true); + themePopup.querySelector("button#" + get_theme()).focus(); + } + + function updateThemeSelected() { + themePopup.querySelectorAll('.theme-selected').forEach(function (el) { + el.classList.remove('theme-selected'); + }); + themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected'); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function get_theme() { + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (theme === null || theme === undefined) { + return default_theme; + } else { + return theme; + } + } + + function set_theme(theme, store = true) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = false; + stylesheets.highlight.disabled = true; + + ace_theme = "ace/theme/tomorrow_night"; + } else if (theme == 'ayu') { + stylesheets.ayuHighlight.disabled = false; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = true; + ace_theme = "ace/theme/tomorrow_night"; + } else { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = false; + ace_theme = "ace/theme/dawn"; + } + + setTimeout(function () { + themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor; + }, 1); + + if (window.ace && window.editors) { + window.editors.forEach(function (editor) { + editor.setTheme(ace_theme); + }); + } + + var previousTheme = get_theme(); + + if (store) { + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + } + + html.classList.remove(previousTheme); + html.classList.add(theme); + updateThemeSelected(); + } + + // Set theme + var theme = get_theme(); + + set_theme(theme, false); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else if (e.target.parentElement.className === "theme") { + theme = e.target.parentElement.id; + } else { + return; + } + set_theme(theme); + }); + + themePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { + hideThemes(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { + hideThemes(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!themePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideThemes(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + themePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + themePopup.querySelector('li:last-child button').focus(); + break; + } + }); +})(); + +(function sidebar() { + var html = document.querySelector("html"); + var sidebar = document.getElementById("sidebar"); + var sidebarLinks = document.querySelectorAll('#sidebar a'); + var sidebarToggleButton = document.getElementById("sidebar-toggle"); + var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); + var firstContact = null; + + function showSidebar() { + html.classList.remove('sidebar-hidden') + html.classList.add('sidebar-visible'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', 0); + }); + sidebarToggleButton.setAttribute('aria-expanded', true); + sidebar.setAttribute('aria-hidden', false); + try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } + } + + + var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle'); + + function toggleSection(ev) { + ev.currentTarget.parentElement.classList.toggle('expanded'); + } + + Array.from(sidebarAnchorToggles).forEach(function (el) { + el.addEventListener('click', toggleSection); + }); + + function hideSidebar() { + html.classList.remove('sidebar-visible') + html.classList.add('sidebar-hidden'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', -1); + }); + sidebarToggleButton.setAttribute('aria-expanded', false); + sidebar.setAttribute('aria-hidden', true); + try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } + } + + // Toggle sidebar + sidebarToggleButton.addEventListener('click', function sidebarToggle() { + if (html.classList.contains("sidebar-hidden")) { + var current_width = parseInt( + document.documentElement.style.getPropertyValue('--sidebar-width'), 10); + if (current_width < 150) { + document.documentElement.style.setProperty('--sidebar-width', '150px'); + } + showSidebar(); + } else if (html.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + sidebarResizeHandle.addEventListener('mousedown', initResize, false); + + function initResize(e) { + window.addEventListener('mousemove', resize, false); + window.addEventListener('mouseup', stopResize, false); + html.classList.add('sidebar-resizing'); + } + function resize(e) { + var pos = (e.clientX - sidebar.offsetLeft); + if (pos < 20) { + hideSidebar(); + } else { + if (html.classList.contains("sidebar-hidden")) { + showSidebar(); + } + pos = Math.min(pos, window.innerWidth - 100); + document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); + } + } + //on mouseup remove windows functions mousemove & mouseup + function stopResize(e) { + html.classList.remove('sidebar-resizing'); + window.removeEventListener('mousemove', resize, false); + window.removeEventListener('mouseup', stopResize, false); + } + + document.addEventListener('touchstart', function (e) { + firstContact = { + x: e.touches[0].clientX, + time: Date.now() + }; + }, { passive: true }); + + document.addEventListener('touchmove', function (e) { + if (!firstContact) + return; + + var curX = e.touches[0].clientX; + var xDiff = curX - firstContact.x, + tDiff = Date.now() - firstContact.time; + + if (tDiff < 250 && Math.abs(xDiff) >= 150) { + if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) + showSidebar(); + else if (xDiff < 0 && curX < 300) + hideSidebar(); + + firstContact = null; + } + }, { passive: true }); + + // Scroll sidebar to current active section + var activeSection = document.getElementById("sidebar").querySelector(".active"); + if (activeSection) { + // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView + activeSection.scrollIntoView({ block: 'center' }); + } +})(); + +(function chapterNavigation() { + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (window.search && window.search.hasFocus()) { return; } + + switch (e.key) { + case 'ArrowRight': + e.preventDefault(); + var nextButton = document.querySelector('.nav-chapters.next'); + if (nextButton) { + window.location.href = nextButton.href; + } + break; + case 'ArrowLeft': + e.preventDefault(); + var previousButton = document.querySelector('.nav-chapters.previous'); + if (previousButton) { + window.location.href = previousButton.href; + } + break; + } + }); +})(); + +(function clipboard() { + var clipButtons = document.querySelectorAll('.clip-button'); + + function hideTooltip(elem) { + elem.firstChild.innerText = ""; + elem.className = 'fa fa-copy clip-button'; + } + + function showTooltip(elem, msg) { + elem.firstChild.innerText = msg; + elem.className = 'fa fa-copy tooltipped'; + } + + var clipboardSnippets = new ClipboardJS('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playground = trigger.closest("pre"); + return playground_text(playground, false); + } + }); + + Array.from(clipButtons).forEach(function (clipButton) { + clipButton.addEventListener('mouseout', function (e) { + hideTooltip(e.currentTarget); + }); + }); + + clipboardSnippets.on('success', function (e) { + e.clearSelection(); + showTooltip(e.trigger, "Copied!"); + }); + + clipboardSnippets.on('error', function (e) { + showTooltip(e.trigger, "Clipboard error!"); + }); +})(); + +(function scrollToTop () { + var menuTitle = document.querySelector('.menu-title'); + + menuTitle.addEventListener('click', function () { + document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); + }); +})(); + +(function controllMenu() { + var menu = document.getElementById('menu-bar'); + + (function controllPosition() { + var scrollTop = document.scrollingElement.scrollTop; + var prevScrollTop = scrollTop; + var minMenuY = -menu.clientHeight - 50; + // When the script loads, the page can be at any scroll (e.g. if you reforesh it). + menu.style.top = scrollTop + 'px'; + // Same as parseInt(menu.style.top.slice(0, -2), but faster + var topCache = menu.style.top.slice(0, -2); + menu.classList.remove('sticky'); + var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster + document.addEventListener('scroll', function () { + scrollTop = Math.max(document.scrollingElement.scrollTop, 0); + // `null` means that it doesn't need to be updated + var nextSticky = null; + var nextTop = null; + var scrollDown = scrollTop > prevScrollTop; + var menuPosAbsoluteY = topCache - scrollTop; + if (scrollDown) { + nextSticky = false; + if (menuPosAbsoluteY > 0) { + nextTop = prevScrollTop; + } + } else { + if (menuPosAbsoluteY > 0) { + nextSticky = true; + } else if (menuPosAbsoluteY < minMenuY) { + nextTop = prevScrollTop + minMenuY; + } + } + if (nextSticky === true && stickyCache === false) { + menu.classList.add('sticky'); + stickyCache = true; + } else if (nextSticky === false && stickyCache === true) { + menu.classList.remove('sticky'); + stickyCache = false; + } + if (nextTop !== null) { + menu.style.top = nextTop + 'px'; + topCache = nextTop; + } + prevScrollTop = scrollTop; + }, { passive: true }); + })(); + (function controllBorder() { + menu.classList.remove('bordered'); + document.addEventListener('scroll', function () { + if (menu.offsetTop === 0) { + menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); + } + }, { passive: true }); + })(); +})(); diff --git a/translations.md b/translations.md deleted file mode 100644 index 8c89dea2..00000000 --- a/translations.md +++ /dev/null @@ -1,6 +0,0 @@ -# Translations - -- [简体中文](https://fomalhauthmj.github.io/patterns/) - -If you want to add a translation, please open an issue in the -[main repository](https://github.com/rust-unofficial/patterns). From e73bbded8aac0a116df96195cef1baeaa9b5fe62 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sat, 8 Apr 2023 02:26:47 +0200 Subject: [PATCH 166/217] Fix typo in CI (#358) --- .env | 2 +- .github/workflows/install-mdbook/action.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 4dae58c1..234d3292 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ MDBOOK_VERSION=0.4.28 -MDBOOK_I8N_HELPERS_VERSION=0.1.0 +MDBOOK_I18N_HELPERS_VERSION=0.1.0 diff --git a/.github/workflows/install-mdbook/action.yml b/.github/workflows/install-mdbook/action.yml index 51a86b1a..e6d46298 100644 --- a/.github/workflows/install-mdbook/action.yml +++ b/.github/workflows/install-mdbook/action.yml @@ -12,11 +12,11 @@ runs: echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" shell: bash - - name: Read mdbook-i8n-helpers version from .env - id: mdbook-i8n-helpers-version + - name: Read mdbook-i18n-helpers version from .env + id: mdbook-i18n-helpers-version run: | . ./.env - echo "::set-output name=MDBOOK_I8N_HELPERS_VERSION::${MDBOOK_I8N_HELPERS_VERSION}" + echo "::set-output name=MDBOOK_I18N_HELPERS_VERSION::${MDBOOK_I18N_HELPERS_VERSION}" shell: bash # The --locked flag is important for reproducible builds. @@ -25,5 +25,5 @@ runs: shell: bash - name: Install i18n-helpers - run: cargo install mdbook-i18n-helpers --locked --version '${{ steps.mdbook-i8n-helpers-version.outputs.MDBOOK_I8N_HELPERS_VERSION }}' + run: cargo install mdbook-i18n-helpers --locked --version '${{ steps.mdbook-i18n-helpers-version.outputs.MDBOOK_I18N_HELPERS_VERSION }}' shell: bash From 36dd3002fba0cb0686465d12d777fb2324b368e7 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 9 Apr 2023 02:58:53 +0200 Subject: [PATCH 167/217] Add cloud-translated pt-BR translation as a starter (#362) --- po/pt-BR.po | 10175 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 10175 insertions(+) create mode 100644 po/pt-BR.po diff --git a/po/pt-BR.po b/po/pt-BR.po new file mode 100644 index 00000000..dea82f36 --- /dev/null +++ b/po/pt-BR.po @@ -0,0 +1,10175 @@ + +msgid "" +msgstr "" +"Project-Id-Version: Rust Design Patterns\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2023-04-08 21:56+0200\n" +"Last-Translator: \n" +"Language-Team: Language pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt-BR\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: src\SUMMARY.md:3 +#, fuzzy +msgid "Introduction" +msgstr "Introdução" + +#: src\SUMMARY.md:4 +#, fuzzy +msgid "Translations" +msgstr "Traduções" + +#: src\SUMMARY.md:5 +#, fuzzy +msgid "Idioms" +msgstr "expressões idiomáticas" + +#: src\SUMMARY.md:6 +#, fuzzy +msgid "Use borrowed types for arguments" +msgstr "Use tipos emprestados para argumentos" + +#: src\SUMMARY.md:7 +#, fuzzy +msgid "Concatenating Strings with format!" +msgstr "Concatenando Strings com formato!" + +#: src\SUMMARY.md:8 +#, fuzzy +msgid "Constructor" +msgstr "Construtor" + +#: src\SUMMARY.md:9 +#, fuzzy +msgid "The Default Trait" +msgstr "A característica padrão" + +#: src\SUMMARY.md:10 +#, fuzzy +msgid "Collections Are Smart Pointers" +msgstr "Coleções são ponteiros inteligentes" + +#: src\SUMMARY.md:11 +#, fuzzy +msgid "Finalisation in Destructors" +msgstr "Finalização em Destruidores" + +#: src\SUMMARY.md:12 +#, fuzzy +msgid "mem::{take(_), replace(_)}" +msgstr "mem::{pegar(_), substituir(_)}" + +#: src\SUMMARY.md:13 +#, fuzzy +msgid "On-Stack Dynamic Dispatch" +msgstr "Despacho dinâmico na pilha" + +#: src\SUMMARY.md:14 src\SUMMARY.md:40 +#, fuzzy +msgid "Foreign function interface (FFI)" +msgstr "Interface de função externa (FFI)" + +#: src\SUMMARY.md:15 +#, fuzzy +msgid "Idiomatic Errors" +msgstr "Erros idiomáticos" + +#: src\SUMMARY.md:16 +#, fuzzy +msgid "Accepting Strings" +msgstr "Aceitando Strings" + +#: src\SUMMARY.md:17 +#, fuzzy +msgid "Passing Strings" +msgstr "Cordas de passagem" + +#: src\SUMMARY.md:18 +#, fuzzy +msgid "Iterating over an Option" +msgstr "Iterando sobre uma opção" + +#: src\SUMMARY.md:19 +#, fuzzy +msgid "Pass Variables to Closure" +msgstr "Passar Variáveis para Encerramento" + +#: src\SUMMARY.md:20 +#, fuzzy +msgid "Privacy For Extensibility" +msgstr "Privacidade para Extensibilidade" + +#: src\SUMMARY.md:21 +#, fuzzy +msgid "Easy doc initialization" +msgstr "Fácil inicialização do documento" + +#: src\SUMMARY.md:22 +#, fuzzy +msgid "Temporary mutability" +msgstr "Mutabilidade temporária" + +#: src\SUMMARY.md:23 +#, fuzzy +msgid "Return consumed arg on error" +msgstr "Retorno arg consumido em caso de erro" + +#: src\SUMMARY.md:25 +#, fuzzy +msgid "Design Patterns" +msgstr "Padrões de design" + +#: src\SUMMARY.md:26 +#, fuzzy +msgid "Behavioural" +msgstr "Comportamental" + +#: src\SUMMARY.md:27 +#, fuzzy +msgid "Command" +msgstr "Comando" + +#: src\SUMMARY.md:28 +#, fuzzy +msgid "Interpreter" +msgstr "Intérprete" + +#: src\SUMMARY.md:29 +#, fuzzy +msgid "Newtype" +msgstr "Newtype" + +#: src\SUMMARY.md:30 +#, fuzzy +msgid "RAII Guards" +msgstr "Guardas RAII" + +#: src\SUMMARY.md:31 +#, fuzzy +msgid "Strategy" +msgstr "Estratégia" + +#: src\SUMMARY.md:32 +#, fuzzy +msgid "Visitor" +msgstr "Visitante" + +#: src\SUMMARY.md:33 +#, fuzzy +msgid "Creational" +msgstr "criacional" + +#: src\SUMMARY.md:34 +#, fuzzy +msgid "Builder" +msgstr "Construtor" + +#: src\SUMMARY.md:35 +#, fuzzy +msgid "Fold" +msgstr "Dobrar" + +#: src\SUMMARY.md:36 +#, fuzzy +msgid "Structural" +msgstr "Estrutural" + +#: src\SUMMARY.md:37 +#, fuzzy +msgid "Compose Structs" +msgstr "Compor Estruturas" + +#: src\SUMMARY.md:38 +#, fuzzy +msgid "Prefer Small Crates" +msgstr "Prefira caixas pequenas" + +#: src\SUMMARY.md:39 +#, fuzzy +msgid "Contain unsafety in small modules" +msgstr "Contenha a insegurança em pequenos módulos" + +#: src\SUMMARY.md:41 +#, fuzzy +msgid "Object-Based APIs" +msgstr "APIs baseadas em objetos" + +#: src\SUMMARY.md:42 +#, fuzzy +msgid "Type Consolidation into Wrappers" +msgstr "Digite a consolidação em wrappers" + +#: src\SUMMARY.md:44 +#, fuzzy +msgid "Anti-patterns" +msgstr "Antipadrões" + +#: src\SUMMARY.md:45 +#, fuzzy +msgid "Clone to satisfy the borrow checker" +msgstr "Clone para satisfazer o verificador de empréstimo" + +#: src\SUMMARY.md:46 +#, fuzzy +msgid "#[deny(warnings)]" +msgstr "#[negar(avisos)]" + +#: src\SUMMARY.md:47 +#, fuzzy +msgid "Deref Polymorphism" +msgstr "Polimorfismo Deref" + +#: src\SUMMARY.md:49 +#, fuzzy +msgid "Functional Programming" +msgstr "Programação Funcional" + +#: src\SUMMARY.md:50 +#, fuzzy +msgid "Programming paradigms" +msgstr "Paradigmas de programação" + +#: src\SUMMARY.md:51 +#, fuzzy +msgid "Generics as Type Classes" +msgstr "Genéricos como Classes de Tipo" + +#: src\SUMMARY.md:52 +#, fuzzy +msgid "Lenses and Prisms" +msgstr "Lentes e Prismas" + +#: src\SUMMARY.md:54 +#, fuzzy +msgid "Additional Resources" +msgstr "Recursos adicionais" + +#: src\SUMMARY.md:55 +#, fuzzy +msgid "Design principles" +msgstr "Princípios de design" + +#: src\intro.md:1 +#, fuzzy +msgid "# Introduction" +msgstr "# Introdução" + +#: src\intro.md:3 +#, fuzzy +msgid "## Participation" +msgstr "## Participação" + +#: src\intro.md:5 +#, fuzzy +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 "" +"Se você estiver interessado em contribuir para este livro, confira o\n" +"[diretrizes de " +"contribuição](https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md)." + +#: src\intro.md:8 +#, fuzzy +msgid "## Design patterns" +msgstr "## Padrões de design" + +#: src\intro.md:10 +#, fuzzy +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 "" +"No desenvolvimento de software, muitas vezes nos deparamos com problemas que " +"compartilham\n" +"semelhanças independentemente do ambiente em que aparecem.\n" +"detalhes de implementação são cruciais para resolver a tarefa em mãos, " +"podemos\n" +"abstrair dessas particularidades para encontrar as práticas comuns que\n" +"são genericamente aplicáveis." + +#: src\intro.md:16 +#, fuzzy +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 "" +"Padrões de projeto são uma coleção de soluções reutilizáveis e testadas " +"para\n" +"problemas recorrentes na engenharia. Eles tornam nosso software mais " +"modular,\n" +"sustentável e extensível. Além disso, esses padrões fornecem uma\n" +"linguagem para desenvolvedores, tornando-os uma excelente ferramenta para\n" +"comunicação na solução de problemas em equipes." + +#: src\intro.md:22 src\patterns/index.md:14 +#, fuzzy +msgid "## Design patterns in Rust" +msgstr "## Padrões de design em Rust" + +#: src\intro.md:24 +#, fuzzy +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 "" +"Rust não é orientado a objetos, e a combinação de todas as suas " +"características,\n" +"como elementos funcionais, um sistema de tipo forte e o verificador de " +"empréstimo,\n" +"torna único.\n" +"Por causa disso, os padrões de projeto do Rust variam em relação a outros\n" +"linguagens de programação tradicionais orientadas a objetos.\n" +"É por isso que decidimos escrever este livro. Esperamos que você goste de " +"lê-lo!\n" +"O livro está dividido em três capítulos principais:" + +#: src\intro.md:32 +#, fuzzy +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 "" +"- [Idioms](./idioms/index.md): orientações a seguir ao codificar.\n" +" Eles são as normas sociais da comunidade.\n" +" Você deve quebrá-los apenas se tiver um bom motivo para isso.\n" +"- [Padrões de design](./patterns/index.md): métodos para resolver problemas " +"comuns\n" +" ao codificar.\n" +"- [Anti-padrões](./anti_patterns/index.md): métodos para resolver problemas " +"comuns\n" +" ao codificar.\n" +" No entanto, embora os padrões de projeto nos tragam benefícios,\n" +" antipadrões criam mais problemas." + +#: src\translations.md:1 +#, fuzzy +msgid "# Translations" +msgstr "# Traduções" + +#: src\translations.md:3 +#, fuzzy +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 "" +"Estamos utilizando " +"[mdbook-i18n-helper](https://github.com/google/mdbook-i18n-helpers).\n" +"Leia sobre como _adicionar_ e _atualizar_ traduções em [seu " +"repositório](https://github.com/google/mdbook-i18n-helpers#creating-and-updating-translations)" + +#: src\translations.md:6 +#, fuzzy +msgid "## External translations" +msgstr "## Traduções externas" + +#: src\translations.md:8 +#, fuzzy +msgid "- [简体中文](https://fomalhauthmj.github.io/patterns/)" +msgstr "- [简体中文](https://fomalhauthmj.github.io/patterns/)" + +#: src\translations.md:10 +#, fuzzy +msgid "" +"If you want to add a translation, please open an issue in the\n" +"[main repository](https://github.com/rust-unofficial/patterns)." +msgstr "" +"Se você quiser adicionar uma tradução, abra um problema no\n" +"[repositório principal](https://github.com/rust-unofficial/patterns)." + +#: src\idioms/index.md:1 +#, fuzzy +msgid "# Idioms" +msgstr "# expressões idiomáticas" + +#: src\idioms/index.md:3 +#, fuzzy +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 "" +"[idiomas](https://en.wikipedia.org/wiki/Programming_idiom) são comumente " +"usados\n" +"estilos, diretrizes e padrões amplamente aceitos por uma comunidade.\n" +"Escrever código idiomático permite que outros desenvolvedores entendam " +"melhor o que é\n" +"acontecendo." + +#: src\idioms/index.md:8 +#, fuzzy +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 "" +"Afinal, o computador só se preocupa com o código de máquina que é gerado\n" +"pelo compilador.\n" +"Em vez disso, o código-fonte é benéfico principalmente para o " +"desenvolvedor.\n" +"Então, já que temos essa camada de abstração, por que não torná-la mais " +"legível?" + +#: 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 +#, fuzzy +msgid "> Code is there for humans, not computers, to understand." +msgstr "> O código existe para ser entendido por humanos, não por computadores." + +#: src\idioms/coercion-arguments.md:1 +#, fuzzy +msgid "# Use borrowed types for arguments" +msgstr "# Use tipos emprestados para argumentos" + +#: 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 +#, fuzzy +msgid "## Description" +msgstr "## Descrição" + +#: src\idioms/coercion-arguments.md:5 +#, fuzzy +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 "" +"Usar um alvo de uma coerção deref pode aumentar a flexibilidade do seu " +"código\n" +"quando você está decidindo qual tipo de argumento usar para um argumento de " +"função.\n" +"Dessa forma, a função aceitará mais tipos de entrada." + +#: src\idioms/coercion-arguments.md:9 +#, fuzzy +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 "" +"Isso não se limita aos tipos de ponteiro fat ou fat.\n" +"Na verdade, você deve sempre preferir usar o **tipo emprestado** em vez de\n" +"**emprestar o tipo próprio**.\n" +"Como `&str` sobre `&String`, `&[T]` sobre `&Vec` ou `&T` sobre `&Box`." + +#: src\idioms/coercion-arguments.md:14 +#, fuzzy +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 "" +"Usando tipos emprestados, você pode evitar camadas de indireção para essas " +"instâncias\n" +"onde o tipo de propriedade já fornece uma camada de indireção. Por exemplo, " +"um\n" +"`String` tem uma camada de indireção, então um `&String` terá duas camadas " +"de\n" +"indireção. Podemos evitar isso usando `&str` e deixando `&String`\n" +"coagir a um `&str` sempre que a função for invocada." + +#: 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 +#, fuzzy +msgid "## Example" +msgstr "## Exemplo" + +#: src\idioms/coercion-arguments.md:22 +#, fuzzy +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 "" +"Para este exemplo, vamos ilustrar algumas diferenças para usar `&String` " +"como um\n" +"argumento de função versus usar um `&str`, mas as ideias também se aplicam " +"ao uso\n" +"`&Vec` versus usar um `&[T]` ou usar um `&Box` versus um `&T`." + +#: src\idioms/coercion-arguments.md:26 +#, fuzzy +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 "" +"Considere um exemplo em que desejamos determinar se uma palavra contém três\n" +"vogais consecutivas. Não precisamos ser os donos da string para determinar " +"isso, então\n" +"vai pegar uma referência." + +#: src\idioms/coercion-arguments.md:30 +#, fuzzy +msgid "The code might look something like this:" +msgstr "O código pode ser algo como isto:" + +#: 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 +#, fuzzy +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 "" +"Isso funciona bem porque estamos passando um tipo `&String` como parâmetro.\n" +"Se removermos os comentários nas duas últimas linhas, o exemplo falhará. " +"Esse\n" +"é porque um tipo `&str` não será forçado a um tipo `&String`. Nós podemos " +"consertar isso\n" +"simplesmente modificando o tipo do nosso argumento." + +#: src\idioms/coercion-arguments.md:67 +#, fuzzy +msgid "For instance, if we change our function declaration to:" +msgstr "Por exemplo, se mudarmos nossa declaração de função para:" + +#: src\idioms/coercion-arguments.md:69 +msgid "" +"```rust, ignore\n" +"fn three_vowels(word: &str) -> bool {\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:73 +#, fuzzy +msgid "then both versions will compile and print the same output." +msgstr "então ambas as versões irão compilar e imprimir a mesma saída." + +#: src\idioms/coercion-arguments.md:75 +msgid "" +"```bash\n" +"Ferris: false\n" +"Curious: true\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:80 +#, fuzzy +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 "" +"Mas espere, isso não é tudo! Há mais nesta história.\n" +"É provável que você diga a si mesmo: isso não importa, eu nunca serei\n" +"usando um `&'static str` como uma entrada de qualquer maneira (como fizemos " +"quando usamos `\"Ferris\"`).\n" +"Mesmo ignorando este exemplo especial, você ainda pode achar que usar " +"`&str`\n" +"dar-lhe mais flexibilidade do que usar um `&String`." + +#: src\idioms/coercion-arguments.md:86 +#, fuzzy +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 "" +"Vamos agora dar um exemplo onde alguém nos dá uma frase, e queremos\n" +"determine se alguma das palavras da frase contém três vogais consecutivas.\n" +"Provavelmente devemos usar a função que já definimos e simplesmente\n" +"alimente cada palavra da frase." + +#: src\idioms/coercion-arguments.md:91 +#, fuzzy +msgid "An example of this could look like this:" +msgstr "Um exemplo disso poderia ser assim:" + +#: 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 +#, fuzzy +msgid "" +"Running this example using our function declared with an argument type " +"`&str`\n" +"will yield" +msgstr "" +"Executando este exemplo usando nossa função declarada com um tipo de " +"argumento `&str`\n" +"vai render" + +#: src\idioms/coercion-arguments.md:124 +msgid "" +"```bash\n" +"curious has three consecutive vowels!\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:128 +#, fuzzy +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 "" +"No entanto, este exemplo não será executado quando nossa função for " +"declarada com um\n" +"tipo de argumento `&String`. Isso ocorre porque as fatias de string são um " +"`&str` e não um\n" +"`&String` que exigiria uma alocação para ser convertida em `&String` que\n" +"não é implícito, enquanto a conversão de `String` para `&str` é barata e " +"implícita." + +#: 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 +#, fuzzy +msgid "## See also" +msgstr "## Veja também" + +#: src\idioms/coercion-arguments.md:135 +#, fuzzy +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 "" +"- [Rust Language Reference on Type " +"Coercions](https://doc.rust-lang.org/reference/type-coercions.html)\n" +"- Para mais discussões sobre como lidar com `String` e `&str` veja\n" +" [esta série de blogs " +"(2015)](https://web.archive.org/web/20201112023149/https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html " +")\n" +" por Herman J. Radtke III" + +#: src\idioms/concat-format.md:1 +#, fuzzy +msgid "# Concatenating strings with `format!`" +msgstr "# Concatenando strings com `format!`" + +#: src\idioms/concat-format.md:5 +#, fuzzy +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 "" +"É possível construir strings usando os métodos `push` e `push_str` em um\n" +"`String` mutável, ou usando seu operador `+`. No entanto, muitas vezes é " +"mais\n" +"conveniente usar `format!`, especialmente onde há uma mistura de literal e\n" +"strings não literais." + +#: 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 +#, fuzzy +msgid "## Advantages" +msgstr "## Vantagens" + +#: src\idioms/concat-format.md:27 +#, fuzzy +msgid "" +"Using `format!` is usually the most succinct and readable way to combine " +"strings." +msgstr "" +"Usar `format!` geralmente é a maneira mais sucinta e legível de combinar " +"strings." + +#: 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 +#, fuzzy +msgid "## Disadvantages" +msgstr "## Desvantagens" + +#: src\idioms/concat-format.md:31 +#, fuzzy +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 "" +"Geralmente não é a maneira mais eficiente de combinar strings - uma série de " +"`push`\n" +"operações em uma string mutável é geralmente a mais eficiente (especialmente " +"se o\n" +"string foi pré-alocada para o tamanho esperado)." + +#: src\idioms/ctor.md:1 +#, fuzzy +msgid "# Constructors\r" +msgstr "# Construtores\r" + +#: src\idioms/ctor.md:3 src\idioms/rustdoc-init.md:3 +#, fuzzy +msgid "## Description\r" +msgstr "## Descrição\r" + +#: src\idioms/ctor.md:5 +#, fuzzy +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 "" +"Rust não possui construtores como uma construção de linguagem. Em vez disso, " +"o\r\n" +"A convenção é usar uma [função associada][função associada] `new` para criar " +"um objeto:" + +#: 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 +#, fuzzy +msgid "## Default Constructors\r" +msgstr "## Construtores Padrão\r" + +#: src\idioms/ctor.md:37 +#, fuzzy +msgid "" +"Rust supports default constructors with the [`Default`][std-default] trait:" +msgstr "" +"Rust suporta construtores padrão com o atributo [`Default`][std-default]:" + +#: 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 +#, fuzzy +msgid "" +"`Default` can also be derived if all types of all fields implement " +"`Default`,\r\n" +"like they do with `Second`:" +msgstr "" +"`Padrão` também pode ser derivado se todos os tipos de todos os campos " +"implementarem `Padrão`,\r\n" +"como eles fazem com `Second`:" + +#: 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 +#, fuzzy +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 "" +"**Observação:** é comum e esperado que os tipos implementem ambos\r\n" +"`Default` e um construtor `new` vazio. `new` é o construtor\r\n" +"convenção em Rust, e os usuários esperam que ela exista, então se for\r\n" +"razoável para o construtor básico não receber argumentos, então\r\n" +"deve, mesmo que seja funcionalmente idêntico ao padrão." + +#: src\idioms/ctor.md:97 +#, fuzzy +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 "" +"**Dica:** A vantagem de implementar ou derivar `Default` é que seu tipo\r\n" +"agora pode ser usado onde uma implementação `Padrão` é necessária, " +"principalmente,\r\n" +"qualquer uma das funções [`*or_default` na biblioteca " +"padrão][std-or-default]." + +#: src\idioms/ctor.md:101 +#, fuzzy +msgid "## See also\r" +msgstr "## Veja também\r" + +#: src\idioms/ctor.md:103 +#, fuzzy +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 "" +"- O [idioma padrão](default.md) para uma descrição mais detalhada do\r\n" +" Traço `Padrão`.\r\n" +"\r\n" +"- O [padrão de construtor](../patterns/creational/builder.md) para " +"construir\r\n" +" objetos onde existem múltiplas configurações.\r\n" +"\r\n" +"- [Diretrizes de API/C-COMMON-TRAITS][Diretrizes de API/C-COMMON-TRAITS] " +"para\r\n" +" implementando ambos, `Default` e `new`.\r\n" +"\r" + +#: src\idioms/default.md:1 +#, fuzzy +msgid "# The `Default` Trait" +msgstr "# A Característica `Padrão`" + +#: 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 +#, fuzzy +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 "" +"Não apenas contêineres de um elemento como `Cow`, `Box` ou `Arc` " +"implementam\n" +"`Default` para tipos `Default` contidos, pode-se automaticamente\n" +"`#[derive(Default)]` para structs cujos campos todos o implementam, então " +"quanto mais\n" +"tipos implementam `Padrão`, mais útil ele se torna." + +#: src\idioms/default.md:16 +#, fuzzy +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 "" +"Por outro lado, os construtores podem receber vários argumentos, enquanto " +"os\n" +"O método `default()` não. Pode até haver vários construtores com\n" +"nomes diferentes, mas só pode haver uma implementação `Padrão` por tipo." + +#: 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 +#, fuzzy +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 "" +"- O idioma [constructor] é outra maneira de gerar instâncias que podem ou " +"podem\n" +" não ser \"padrão\"\n" +"- A documentação [`Padrão`] (role para baixo para ver a lista de " +"implementadores)\n" +"- [`Option::unwrap_or_default()`]\n" +"- [`derivar(novo)`]" + +#: src\idioms/deref.md:1 +#, fuzzy +msgid "# Collections are smart pointers" +msgstr "# Coleções são ponteiros inteligentes" + +#: src\idioms/deref.md:5 +#, fuzzy +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 "" +"Use o [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\n" +"característica para tratar coleções como ponteiros inteligentes, oferecendo " +"propriedade\n" +"e visualizações de dados emprestadas." + +#: 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 +#, fuzzy +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 "" +"Um `Vec` é uma coleção proprietária de `T`s, enquanto uma fatia (`&[T]`) " +"é um empréstimo\n" +"coleção de `T`s. A implementação de `Deref` para `Vec` permite a " +"desreferência implícita\n" +"de `&Vec` para `&[T]` e inclui o relacionamento na desativação " +"automática\n" +"pesquisas. A maioria dos métodos que você pode esperar que sejam " +"implementados para `Vec`s são\n" +"implementado para fatias." + +#: src\idioms/deref.md:34 +#, fuzzy +msgid "Also `String` and `&str` have a similar relation." +msgstr "Além disso, `String` e `&str` têm uma relação semelhante." + +#: 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 +#, fuzzy +msgid "## Motivation" +msgstr "## Motivação" + +#: src\idioms/deref.md:38 +#, fuzzy +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 "" +"Propriedade e empréstimo são aspectos-chave da linguagem Rust. Estruturas de " +"dados\n" +"deve levar em conta essas semânticas adequadamente para dar a um bom " +"usuário\n" +"experiência. Ao implementar uma estrutura de dados proprietária de seus " +"dados, oferecendo uma\n" +"A visão emprestada desses dados permite APIs mais flexíveis." + +#: src\idioms/deref.md:45 +#, fuzzy +msgid "" +"Most methods can be implemented only for the borrowed view, they are then\n" +"implicitly available for the owning view." +msgstr "" +"A maioria dos métodos pode ser implementada apenas para a visão emprestada, " +"eles são então\n" +"implicitamente disponível para a exibição proprietária." + +#: src\idioms/deref.md:48 +#, fuzzy +msgid "Gives clients a choice between borrowing or taking ownership of data." +msgstr "" +"Dá aos clientes a escolha entre tomar emprestado ou se apropriar dos dados." + +#: src\idioms/deref.md:52 +#, fuzzy +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 "" +"Métodos e características disponíveis apenas por desreferenciação não são " +"levados em consideração\n" +"ao verificar limites, então programação genérica com estruturas de dados " +"usando este\n" +"padrão pode se tornar complexo (veja as características `Borrow` e `AsRef`, " +"etc.)." + +#: 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 +#, fuzzy +msgid "## Discussion" +msgstr "## Discussão" + +#: src\idioms/deref.md:58 +#, fuzzy +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 "" +"Ponteiros inteligentes e coleções são análogos: um ponteiro inteligente " +"aponta para um único\n" +"objeto, enquanto uma coleção aponta para muitos objetos. Do ponto de vista " +"de\n" +"o sistema de tipo, há pouca diferença entre os dois. Uma coleção possui\n" +"seus dados se a única forma de acesso a cada dado for através da coleta e " +"do\n" +"coleta é responsável por excluir os dados (mesmo em casos de " +"compartilhamento\n" +"propriedade, algum tipo de visão emprestada pode ser apropriada). Se uma " +"coleção possui\n" +"seus dados, geralmente é útil fornecer uma visão dos dados como emprestados " +"para que\n" +"pode ser referenciado várias vezes." + +#: src\idioms/deref.md:67 +#, fuzzy +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 "" +"A maioria dos ponteiros inteligentes (por exemplo, `Foo`) implementam " +"`Deref`. No entanto,\n" +"as coleções geralmente desreferenciarão a um tipo personalizado. `[T]` e " +"`str` têm alguns\n" +"suporte a idiomas, mas no caso geral, isso não é necessário. `Foo` pode\n" +"implemente `Deref>` onde `Bar` é um tipo de tamanho dinâmico " +"e\n" +"`&Bar` é uma visão emprestada dos dados em `Foo`." + +#: src\idioms/deref.md:73 +#, fuzzy +msgid "" +"Commonly, ordered collections will implement `Index` for `Range`s to " +"provide\n" +"slicing syntax. The target will be the borrowed view." +msgstr "" +"Normalmente, coleções ordenadas irão implementar `Index` para `Range`s para " +"fornecer\n" +"sintaxe de corte. O alvo será a visão emprestada." + +#: src\idioms/deref.md:78 +#, fuzzy +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 "" +"- [Deref polimorfismo anti-padrão](../anti_patterns/deref.md).\n" +"- [Documentação para o trait " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\idioms/dtor-finally.md:1 +#, fuzzy +msgid "# Finalisation in destructors" +msgstr "# Finalização em destrutores" + +#: src\idioms/dtor-finally.md:5 +#, fuzzy +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 "" +"Rust não fornece o equivalente aos blocos `finally` - código que será\n" +"executado, não importa como uma função é encerrada. Em vez disso, o " +"destruidor de um objeto pode\n" +"ser usado para executar o código que deve ser executado antes da saída." + +#: 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 +#, fuzzy +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 "" +"Se uma função tiver vários pontos de retorno, a execução do código na saída " +"torna-se\n" +"difícil e repetitivo (e, portanto, propenso a erros). Este é especialmente o " +"caso onde\n" +"o retorno é implícito devido a uma macro. Um caso comum é o operador `?` " +"que\n" +"retorna se o resultado for um `Err`, mas continua se for `Ok`. `?` é usado " +"como\n" +"um mecanismo de manipulação de exceção, mas ao contrário de Java (que tem " +"`finally`), há\n" +"não há como agendar o código para execução em casos normais e excepcionais.\n" +"Entrar em pânico também sairá de uma função mais cedo." + +#: src\idioms/dtor-finally.md:44 +#, fuzzy +msgid "" +"Code in destructors will (nearly) always be run - copes with panics, early\n" +"returns, etc." +msgstr "" +"O código em destruidores será (quase) sempre executado - lida com pânicos,\n" +"devoluções, etc" + +#: src\idioms/dtor-finally.md:49 +#, fuzzy +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 "" +"Não é garantido que os destruidores serão executados. Por exemplo, se houver " +"um\n" +"loop infinito em uma função ou se a execução de uma função falhar antes de " +"sair.\n" +"Os destruidores também não são executados no caso de um pânico em um já em " +"pânico\n" +"fio. Portanto, os destruidores não podem ser usados como finalizadores onde " +"é\n" +"absolutamente essencial que a finalização aconteça." + +#: src\idioms/dtor-finally.md:55 +#, fuzzy +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 "" +"Esse padrão introduz algum código implícito difícil de perceber. Lendo uma " +"função\n" +"não dá nenhuma indicação clara de destruidores a serem executados na saída. " +"isso pode fazer\n" +"depuração complicada." + +#: src\idioms/dtor-finally.md:59 +#, fuzzy +msgid "" +"Requiring an object and `Drop` impl just for finalisation is heavy on " +"boilerplate." +msgstr "" +"Exigir um objeto e impl `Drop` apenas para finalização é pesado em clichê." + +#: src\idioms/dtor-finally.md:63 +#, fuzzy +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 "" +"Existe alguma sutileza sobre como exatamente armazenar o objeto usado como " +"um\n" +"finalizador. Deve ser mantido vivo até o final da função e deve então ser\n" +"destruído. O objeto deve ser sempre um valor ou um ponteiro de propriedade " +"exclusiva (por exemplo,\n" +"`Box`). Se um ponteiro compartilhado (como `Rc`) for usado, o " +"finalizador pode\n" +"ser mantido vivo além do tempo de vida da função. Por razões semelhantes, o\n" +"finalizer não deve ser movido ou retornado." + +#: src\idioms/dtor-finally.md:70 +#, fuzzy +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 "" +"O finalizador deve ser atribuído a uma variável, caso contrário, será " +"destruído\n" +"imediatamente, em vez de quando sai do escopo. O nome da variável deve " +"começar\n" +"com `_` se a variável for usada apenas como finalizador, caso contrário, o " +"compilador\n" +"avisará que o finalizador nunca é usado. No entanto, não chame a variável\n" +"`_` sem sufixo - nesse caso será destruído imediatamente." + +#: src\idioms/dtor-finally.md:76 +#, fuzzy +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 "" +"No Rust, os destruidores são executados quando um objeto sai do escopo. Isto " +"acontece\n" +"se chegamos ao final do bloco, há um retorno antecipado ou o programa\n" +"pânico. Ao entrar em pânico, Rust desenrola a pilha executando destruidores " +"para cada\n" +"objeto em cada quadro de pilha. Assim, os destruidores são chamados mesmo " +"que o pânico aconteça\n" +"em uma função que está sendo chamada." + +#: src\idioms/dtor-finally.md:82 +#, fuzzy +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 "" +"Se um destruidor entrar em pânico enquanto desenrola, não há nenhuma boa " +"ação a ser tomada, então Rust\n" +"aborta o thread imediatamente, sem executar mais destruidores. Isso " +"significa\n" +"que os destruidores não são absolutamente garantidos para serem executados. " +"Também significa que você\n" +"deve tomar cuidado extra em seus destruidores para não entrar em pânico, " +"pois pode deixar\n" +"recursos em um estado inesperado." + +#: src\idioms/dtor-finally.md:90 +#, fuzzy +msgid "[RAII guards](../patterns/behavioural/RAII.md)." +msgstr "[guardas RAII](../patterns/behavioural/RAII.md)." + +#: src\idioms/mem-replace.md:1 +#, fuzzy +msgid "# `mem::{take(_), replace(_)}` to keep owned values in changed enums" +msgstr "" +"# `mem::{take(_), replace(_)}` para manter os valores de propriedade em " +"enums alterados" + +#: src\idioms/mem-replace.md:5 +#, fuzzy +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 "" +"Digamos que temos um `&mut MyEnum` que tem (pelo menos) duas variantes,\n" +"`A { nome: String, x: u8 }` e `B { nome: String }`. Agora queremos mudar\n" +"`MyEnum::A` para um `B` se `x` for zero, enquanto mantém `MyEnum::B` intacto." + +#: src\idioms/mem-replace.md:9 +#, fuzzy +msgid "We can do this without cloning the `name`." +msgstr "Podemos fazer isso sem clonar o `name`." + +#: 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 +#, fuzzy +msgid "This also works with more variants:" +msgstr "Isso também funciona com mais variantes:" + +#: 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 +#, fuzzy +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 "" +"Ao trabalhar com enums, podemos querer alterar um valor de enum no lugar, " +"talvez\n" +"para outra variante. Isso geralmente é feito em duas fases para manter o " +"empréstimo\n" +"verificador feliz. Na primeira fase, observamos o valor existente e " +"procuramos\n" +"suas partes para decidir o que fazer a seguir. Na segunda fase, podemos " +"condicionalmente\n" +"altere o valor (como no exemplo acima)." + +#: src\idioms/mem-replace.md:65 +#, fuzzy +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 "" +"O verificador de empréstimo não nos permitirá remover `name` do enum " +"(porque\n" +"_algo_ deve estar lá.) É claro que poderíamos nomear `.clone()` e colocar o " +"clone\n" +"em nosso `MyEnum::B`, mas isso seria uma instância do anti-padrão [Clone " +"para satisfazer o verificador de " +"empréstimo](../anti_patterns/borrow_clone.md). De qualquer forma, nós\n" +"pode evitar a alocação extra alterando `e` apenas com um empréstimo mutável." + +#: src\idioms/mem-replace.md:70 +#, fuzzy +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 "" +"`mem::take` nos permite trocar o valor, substituindo-o por seu valor " +"padrão,\n" +"e retornando o valor anterior. Para `String`, o valor padrão é um vazio\n" +"`String`, que não precisa alocar. Como resultado, obtemos o original\n" +"`name` _como um valor de propriedade_. Podemos então envolver isso em outro " +"enum." + +#: src\idioms/mem-replace.md:75 +#, fuzzy +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 "" +"**NOTA:** `mem::replace` é muito semelhante, mas nos permite especificar o " +"que\n" +"substitua o valor por. Um equivalente à nossa linha `mem::take` seria\n" +"`mem::replace(nome, String::new())`." + +#: src\idioms/mem-replace.md:79 +#, fuzzy +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 "" +"Observe, no entanto, que se estivermos usando uma `Option` e quisermos " +"substituir sua\n" +"valor com um `None`, o método `take()` de `Option` fornece um valor mais " +"curto e\n" +"alternativa mais idiomática." + +#: src\idioms/mem-replace.md:85 +#, fuzzy +msgid "" +"Look ma, no allocation! Also you may feel like Indiana Jones while doing it." +msgstr "" +"Olha ma, sem alocação! Além disso, você pode se sentir como Indiana Jones ao " +"fazê-lo." + +#: src\idioms/mem-replace.md:89 +#, fuzzy +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 "" +"Isso fica um pouco prolixo. Errar repetidamente fará com que você odeie o\n" +"verificador de empréstimo. O compilador pode falhar ao otimizar o " +"armazenamento duplo,\n" +"resultando em desempenho reduzido em oposição ao que você faria em ambientes " +"inseguros\n" +"línguas." + +#: src\idioms/mem-replace.md:94 +#, fuzzy +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 "" +"Além disso, o tipo que você está tomando precisa implementar o [traço " +"`Default`](./default.md). No entanto, se o tipo com o qual você está " +"trabalhando não\n" +"implementar isso, você pode usar `mem::replace`." + +#: src\idioms/mem-replace.md:99 +#, fuzzy +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 "" +"Esse padrão é interessante apenas no Rust. Em idiomas GC'd, você pegaria o\n" +"referência ao valor por padrão (e o GC manteria o controle de refs), e em\n" +"outras linguagens de baixo nível, como C, você simplesmente criaria um alias " +"para o ponteiro e consertaria as coisas\n" +"mais tarde." + +#: src\idioms/mem-replace.md:104 +#, fuzzy +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 "" +"No entanto, no Rust, temos que trabalhar um pouco mais para fazer isso. Um " +"valor de propriedade\n" +"pode ter apenas um dono, então, para retirá-lo, precisamos colocar algo de " +"volta –\n" +"como Indiana Jones, substituindo o artefato por um saco de areia." + +#: src\idioms/mem-replace.md:110 +#, fuzzy +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 "" +"Isso elimina o [Clone para satisfazer o verificador de " +"empréstimo](../anti_patterns/borrow_clone.md)\n" +"antipadrão em um caso específico." + +#: src\idioms/on-stack-dyn-dispatch.md:1 +#, fuzzy +msgid "# On-Stack Dynamic Dispatch" +msgstr "# Despacho Dinâmico On-Stack" + +#: src\idioms/on-stack-dyn-dispatch.md:5 +#, fuzzy +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 "" +"Podemos despachar dinamicamente vários valores, no entanto, para fazer isso, " +"precisamos\n" +"para declarar várias variáveis para vincular objetos de tipos diferentes. " +"Para estender o\n" +"tempo de vida conforme necessário, podemos usar a inicialização condicional " +"adiada, como visto\n" +"abaixo:" + +#: 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 +#, fuzzy +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 "" +"Rust monomorfiza o código por padrão. Isso significa que uma cópia do código " +"será\n" +"gerado para cada tipo com o qual é usado e otimizado independentemente. " +"Enquanto isso\n" +"permite um código muito rápido no hot path, também incha o código em locais\n" +"onde o desempenho não é essencial, custando assim tempo de compilação e " +"cache\n" +"uso." + +#: src\idioms/on-stack-dyn-dispatch.md:45 +#, fuzzy +msgid "" +"Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " +"ask\n" +"for it." +msgstr "" +"Felizmente, o Rust nos permite usar o dispatch dinâmico, mas temos que " +"perguntar explicitamente\n" +"para isso." + +#: src\idioms/on-stack-dyn-dispatch.md:50 +#, fuzzy +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 "" +"Não precisamos alocar nada no heap. Nem nós precisamos\n" +"inicializar algo que não usaremos mais tarde, nem precisamos monomorfizar o\n" +"todo o código que segue para funcionar com `File` ou `Stdin`." + +#: src\idioms/on-stack-dyn-dispatch.md:56 +#, fuzzy +msgid "The code needs more moving parts than the `Box`-based version:" +msgstr "O código precisa de mais partes móveis do que a versão baseada em `Box`:" + +#: 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 +#, fuzzy +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 "" +"Os recém-chegados ao Rust geralmente aprenderão que o Rust exige que todas " +"as variáveis sejam\n" +"inicializado _antes de usar_, então é fácil ignorar o fato de que _não " +"usado_\n" +"as variáveis podem muito bem ser não inicializadas. Rust trabalha bastante " +"para garantir que este\n" +"funciona bem e apenas os valores inicializados são descartados no final de " +"sua\n" +"escopo." + +#: src\idioms/on-stack-dyn-dispatch.md:76 +#, fuzzy +msgid "The example meets all the constraints Rust places on us:" +msgstr "O exemplo atende a todas as restrições que Rust nos impõe:" + +#: src\idioms/on-stack-dyn-dispatch.md:78 +#, fuzzy +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 "" +"- Todas as variáveis são inicializadas antes de serem usadas (neste caso, " +"emprestadas)\n" +"- Cada variável contém apenas valores de um único tipo. Em nosso exemplo, " +"`stdin` é\n" +" do tipo `Stdin`, `file` é do tipo `File` e `readable` é do tipo `&mut dyn " +"Read`\n" +"- Cada valor emprestado sobrevive a todas as referências emprestadas dele" + +#: src\idioms/on-stack-dyn-dispatch.md:85 +#, fuzzy +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 "" +"- [Finalização em destruidores](dtor-finally.md) e\n" +" [guardas RAII](../patterns/behavioural/RAII.md) podem se beneficiar de um " +"controle rígido sobre\n" +" vidas.\n" +"- Para `Option<&T>`s de referências (mutáveis) preenchidas condicionalmente, " +"pode-se\n" +" inicialize um `Option` diretamente e use seu método [`.as_ref()`] para " +"obter um\n" +" referência opcional." + +#: src\idioms/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Idioms" +msgstr "# Idiomas FFI" + +#: src\idioms/ffi/intro.md:3 +#, fuzzy +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 "" +"Escrever código FFI é um curso completo em si.\n" +"No entanto, existem vários idiomas aqui que podem atuar como ponteiros e " +"evitar\n" +"armadilhas para usuários inexperientes de Rust `inseguro`." + +#: src\idioms/ffi/intro.md:7 +#, fuzzy +msgid "This section contains idioms that may be useful when doing FFI." +msgstr "" +"Esta seção contém expressões idiomáticas que podem ser úteis ao fazer FFI." + +#: src\idioms/ffi/intro.md:9 +#, fuzzy +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 "" +"1. [Erros idiomáticos](./errors.md) - Tratamento de erros com códigos " +"inteiros e\n" +" valores de retorno do sentinela (como ponteiros `NULL`)\n" +"\n" +"2. [Accepting Strings](./accepting-strings.md) com o mínimo de código " +"inseguro\n" +"\n" +"3. [Passing Strings](./passing-strings.md) para funções FFI" + +#: src\idioms/ffi/errors.md:1 +#, fuzzy +msgid "# Error Handling in FFI" +msgstr "# Tratamento de erros no FFI" + +#: src\idioms/ffi/errors.md:5 +#, fuzzy +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 "" +"Em idiomas estrangeiros como C, os erros são representados por códigos de " +"retorno.\n" +"No entanto, o sistema de tipos do Rust permite que informações de erro muito " +"mais ricas sejam\n" +"capturado e propagado através de um tipo completo." + +#: src\idioms/ffi/errors.md:9 +#, fuzzy +msgid "" +"This best practice shows different kinds of error codes, and how to expose " +"them\n" +"in a usable way:" +msgstr "" +"Esta prática recomendada mostra diferentes tipos de códigos de erro e como " +"expô-los\n" +"de forma utilizável:" + +#: src\idioms/ffi/errors.md:12 +#, fuzzy +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 "" +"1. Flat Enums devem ser convertidos em inteiros e retornados como códigos.\n" +"2. Enums estruturados devem ser convertidos em um código inteiro com um erro " +"de string\n" +" mensagem para detalhes.\n" +"3. Tipos de erro personalizados devem se tornar \"transparentes\", com uma " +"representação em C." + +#: 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 +#, fuzzy +msgid "## Code Example" +msgstr "## Exemplo de Código" + +#: src\idioms/ffi/errors.md:19 +#, fuzzy +msgid "### Flat Enums" +msgstr "### Enums Simples" + +#: 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 +#, fuzzy +msgid "### Structured Enums" +msgstr "### Enums estruturados" + +#: 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 +#, fuzzy +msgid "### Custom Error Types" +msgstr "### Tipos de erro personalizados" + +#: 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 +#, fuzzy +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 "" +"Isso garante que o idioma estrangeiro tenha acesso claro às informações de " +"erro\n" +"sem comprometer a API do código Rust." + +#: src\idioms/ffi/errors.md:138 +#, fuzzy +msgid "" +"It's a lot of typing, and some types may not be able to be converted easily\n" +"to C." +msgstr "" +"É muita digitação e alguns tipos podem não ser convertidos facilmente\n" +"para C." + +#: src\idioms/ffi/accepting-strings.md:1 +#, fuzzy +msgid "# Accepting Strings" +msgstr "# Aceitando Strings" + +#: src\idioms/ffi/accepting-strings.md:5 +#, fuzzy +msgid "" +"When accepting strings via FFI through pointers, there are two principles " +"that\n" +"should be followed:" +msgstr "" +"Ao aceitar strings via FFI por meio de ponteiros, existem dois princípios " +"que\n" +"deve ser seguido:" + +#: src\idioms/ffi/accepting-strings.md:8 +#, fuzzy +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 "" +"1. Mantenha strings estrangeiras \"emprestadas\", em vez de copiá-las " +"diretamente.\n" +"2. Minimize a complexidade e o código \"inseguro\" envolvido na conversão\n" +" de uma string estilo C para strings Rust nativas." + +#: src\idioms/ffi/accepting-strings.md:14 +#, fuzzy +msgid "" +"The strings used in C have different behaviours to those used in Rust, " +"namely:" +msgstr "" +"As strings usadas em C possuem comportamentos diferentes das usadas em Rust, " +"a saber:" + +#: src\idioms/ffi/accepting-strings.md:16 +#, fuzzy +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 "" +"- As strings C são terminadas em nulo, enquanto as strings Rust armazenam " +"seu comprimento\n" +"- As strings C podem conter qualquer byte arbitrário diferente de zero, " +"enquanto as strings Rust devem ser\n" +" UTF-8\n" +"- Strings C são acessadas e manipuladas usando operações de ponteiro " +"`inseguras`\n" +" enquanto as interações com strings Rust passam por métodos seguros" + +#: src\idioms/ffi/accepting-strings.md:22 +#, fuzzy +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 "" +"A biblioteca padrão do Rust vem com equivalentes em C de `String` e `&str` " +"do Rust\n" +"chamados `CString` e `&CStr`, que nos permitem evitar muita complexidade\n" +"e código `inseguro` envolvido na conversão entre strings C e strings Rust." + +#: src\idioms/ffi/accepting-strings.md:26 +#, fuzzy +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 "" +"O tipo `&CStr` também nos permite trabalhar com dados emprestados, ou seja, " +"passar\n" +"strings entre Rust e C é uma operação de custo zero." + +#: 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 +#, fuzzy +msgid "The example is is written to ensure that:" +msgstr "O exemplo foi escrito para garantir que:" + +#: src\idioms/ffi/accepting-strings.md:72 +#, fuzzy +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 "" +"1. O bloco `unsafe` é o menor possível.\n" +"2. O ponteiro com um tempo de vida \"não rastreado\" torna-se um " +"\"rastreado\" compartilhado\n" +" referência" + +#: src\idioms/ffi/accepting-strings.md:76 +#, fuzzy +msgid "Consider an alternative, where the string is actually copied:" +msgstr "Considere uma alternativa, onde a string é realmente copiada:" + +#: 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 +#, fuzzy +msgid "This code in inferior to the original in two respects:" +msgstr "Este código é inferior ao original em dois aspectos:" + +#: src\idioms/ffi/accepting-strings.md:122 +#, fuzzy +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 "" +"1. Há muito mais código \"inseguro\" e, mais importante, mais invariantes\n" +" deve sustentar.\n" +"2. Devido à extensa aritmética necessária, há um bug nesta versão\n" +" que casos Rust `comportamento indefinido`." + +#: src\idioms/ffi/accepting-strings.md:127 +#, fuzzy +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 "" +"O bug aqui é um erro simples na aritmética do ponteiro: a string foi " +"copiada,\n" +"todos os bytes `msg_len` dele. No entanto, o terminador `NUL` no final não " +"era." + +#: src\idioms/ffi/accepting-strings.md:130 +#, fuzzy +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 "" +"O vetor então teve seu tamanho _definido_ para o comprimento da _string " +"preenchida com zero_ --\n" +"em vez de _redimensionado_ a ele, o que poderia ter adicionado um zero no " +"final.\n" +"Como resultado, o último byte no Vector é memória não inicializada.\n" +"Quando o `CString` é criado na parte inferior do bloco, sua leitura do\n" +"O vetor causará `comportamento indefinido`!" + +#: src\idioms/ffi/accepting-strings.md:136 +#, fuzzy +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 "" +"Como muitos desses problemas, esse seria um problema difícil de rastrear.\n" +"Às vezes entrava em pânico porque a string não era `UTF-8`, às vezes\n" +"colocar um caractere estranho no final da string, às vezes seria apenas\n" +"travar completamente." + +#: src\idioms/ffi/accepting-strings.md:143 +#: src\idioms/ffi/passing-strings.md:105 +#, fuzzy +msgid "None?" +msgstr "Nenhum?" + +#: src\idioms/ffi/passing-strings.md:1 +#, fuzzy +msgid "# Passing Strings" +msgstr "# Passando Cordas" + +#: src\idioms/ffi/passing-strings.md:5 +#, fuzzy +msgid "" +"When passing strings to FFI functions, there are four principles that should " +"be\n" +"followed:" +msgstr "" +"Ao passar strings para funções FFI, existem quatro princípios que devem ser\n" +"seguido:" + +#: src\idioms/ffi/passing-strings.md:8 +#, fuzzy +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 "" +"1. Faça com que a vida útil das strings próprias seja a maior possível.\n" +"2. Minimize o código `inseguro` durante a conversão.\n" +"3. Se o código C puder modificar os dados da string, use `Vec` em vez de " +"`CString`.\n" +"4. A menos que a API de função externa exija, a propriedade da string\n" +" não deve transferir para o receptor." + +#: src\idioms/ffi/passing-strings.md:16 +#, fuzzy +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 "" +"Rust tem suporte embutido para strings no estilo C com seus `CString` e " +"`CStr`\n" +"tipos. No entanto, existem diferentes abordagens que podem ser adotadas com " +"strings que\n" +"estão sendo enviados para uma chamada de função estrangeira de uma função " +"Rust." + +#: src\idioms/ffi/passing-strings.md:20 +#, fuzzy +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 "" +"A melhor prática é simples: use `CString` de forma a minimizar\n" +"código `inseguro`. No entanto, uma advertência secundária é que\n" +"_o objeto deve viver o suficiente_, o que significa que o tempo de vida deve " +"ser maximizado.\n" +"Além disso, a documentação explica que \"transmitir\" um `CString` após\n" +"modificação é UB, então trabalho adicional é necessário nesse caso." + +#: 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 +#, fuzzy +msgid "The example is written in a way to ensure that:" +msgstr "O exemplo é escrito de forma a garantir que:" + +#: src\idioms/ffi/passing-strings.md:72 +#, fuzzy +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 "" +"1. O bloco `unsafe` é o menor possível.\n" +"2. O `CString` vive o suficiente.\n" +"3. Erros com typecasts são sempre propagados quando possível." + +#: src\idioms/ffi/passing-strings.md:76 +#, fuzzy +msgid "" +"A common mistake (so common it's in the documentation) is to not use the\n" +"variable in the first block:" +msgstr "" +"Um erro comum (tão comum que está na documentação) é não usar o\n" +"variável no primeiro bloco:" + +#: 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 +#, fuzzy +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 "" +"Este código resultará em um ponteiro pendente, porque o tempo de vida do\n" +"`CString` não é estendido pela criação do ponteiro, ao contrário de uma " +"referência\n" +"criada." + +#: src\idioms/ffi/passing-strings.md:98 +#, fuzzy +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 "" +"Outra questão frequentemente levantada é que a inicialização de um vetor 1k " +"de\n" +"zeros é \"lento\". No entanto, versões recentes do Rust realmente otimizam " +"isso\n" +"macro específica para uma chamada para `zmalloc`, o que significa que é tão " +"rápido quanto a operação\n" +"a capacidade do sistema de retornar memória zerada (o que é bastante rápido)." + +#: src\idioms/option-iter.md:1 +#, fuzzy +msgid "# Iterating over an `Option`" +msgstr "# Iterando sobre uma `Option`" + +#: src\idioms/option-iter.md:5 +#, fuzzy +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 "" +"`Option` pode ser visto como um contêiner que contém zero ou um\n" +"elemento. Em particular, ele implementa o recurso `IntoIterator` e, como " +"tal,\n" +"pode ser usado com código genérico que precisa desse tipo." + +#: src\idioms/option-iter.md:9 src\patterns/structural/small-crates.md:34 +#: src\patterns/structural/unsafe-mods.md:22 +#, fuzzy +msgid "## Examples" +msgstr "## Exemplos" + +#: src\idioms/option-iter.md:11 +#, fuzzy +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 "" +"Como `Option` implementa `IntoIterator`, ele pode ser usado como um " +"argumento para\n" +"[`.extend()`](https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend):" + +#: 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 +#, fuzzy +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 "" +"Se você precisar adicionar uma `Option` ao final de um iterador existente, " +"você pode\n" +"passe para " +"[`.chain()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain):" + +#: 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 +#, fuzzy +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 "" +"Note que se `Option` for sempre `Some`, então é mais idiomático usar\n" +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) no\n" +"elemento em vez disso." + +#: src\idioms/option-iter.md:42 +#, fuzzy +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 "" +"Além disso, como `Option` implementa `IntoIterator`, é possível iterar " +"sobre\n" +"usando um loop `for`. Isso é equivalente a combiná-lo com `if let " +"Some(..)`,\n" +"e na maioria dos casos você deve preferir o último." + +#: src\idioms/option-iter.md:48 +#, fuzzy +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 "" +"- [`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) é um\n" +" iterator que produz exatamente um elemento. É uma alternativa mais legível " +"para\n" +" `Some(foo).into_iter()`.\n" +"\n" +"- " +"[`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map)\n" +" é uma versão do " +"[`Iterator::map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map),\n" +" especializado para funções de mapeamento que retornam `Option`.\n" +"\n" +"- A caixa [`ref_slice`](https://crates.io/crates/ref_slice) fornece funções\n" +" para converter uma `Opção` em uma fatia de zero ou um elemento.\n" +"\n" +"- [Documentação para " +"`Option`](https://doc.rust-lang.org/std/option/enum.Option.html)" + +#: src\idioms/pass-var-to-closure.md:1 +#, fuzzy +msgid "# Pass variables to closure" +msgstr "# Passa variáveis para encerramento" + +#: src\idioms/pass-var-to-closure.md:5 +#, fuzzy +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 "" +"Por padrão, os fechamentos capturam seu ambiente por empréstimo. Ou você " +"pode usar\n" +"fechamento `move` para mover todo o ambiente. No entanto, muitas vezes você " +"deseja mover apenas\n" +"algumas variáveis para fechamento, dar-lhe cópia de alguns dados, passá-lo " +"por referência ou\n" +"realizar alguma outra transformação." + +#: src\idioms/pass-var-to-closure.md:10 +#, fuzzy +msgid "Use variable rebinding in separate scope for that." +msgstr "Use a religação de variável em escopo separado para isso." + +#: src\idioms/pass-var-to-closure.md:14 +#, fuzzy +msgid "Use" +msgstr "Usar" + +#: 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 +#, fuzzy +msgid "instead of" +msgstr "em vez de" + +#: 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 +#, fuzzy +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 "" +"Os dados copiados são agrupados com a definição de fechamento, portanto, sua " +"finalidade é\n" +"mais claros, e eles serão descartados imediatamente, mesmo que não sejam " +"consumidos\n" +"por fechamento." + +#: src\idioms/pass-var-to-closure.md:54 +#, fuzzy +msgid "" +"Closure uses same variable names as surrounding code whether data are copied " +"or\n" +"moved." +msgstr "" +"Closure usa os mesmos nomes de variáveis que o código ao redor, sejam os " +"dados copiados ou\n" +"mudou-se." + +#: src\idioms/pass-var-to-closure.md:59 +#, fuzzy +msgid "Additional indentation of closure body." +msgstr "Recuo adicional do corpo da tampa." + +#: src\idioms/priv-extend.md:1 +#, fuzzy +msgid "# `#[non_exhaustive]` and private fields for extensibility" +msgstr "# `#[non_exhaustive]` e campos privados para extensibilidade" + +#: src\idioms/priv-extend.md:5 +#, fuzzy +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 "" +"Existe um pequeno conjunto de cenários em que um autor de biblioteca pode " +"querer adicionar\n" +"campos para uma estrutura pública ou novas variantes para uma enumeração sem " +"quebrar para trás\n" +"compatibilidade." + +#: src\idioms/priv-extend.md:9 +#, fuzzy +msgid "Rust offers two solutions to this problem:" +msgstr "Rust oferece duas soluções para este problema:" + +#: src\idioms/priv-extend.md:11 +#, fuzzy +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 "" +"- Use `#[non_exhaustive]` nas variantes `struct`s, `enum`s e `enum`.\n" +" Para documentação extensa sobre todos os lugares onde `#[non_exhaustive]` " +"pode ser\n" +" usado, consulte [os " +"documentos](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).\n" +"\n" +"- Você pode adicionar um campo privado a uma estrutura para evitar que ela " +"seja diretamente\n" +" instanciado ou comparado (ver Alternativa)" + +#: 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 +#, fuzzy +msgid "## Alternative: `Private fields` for structs" +msgstr "## Alternativa: `Campos privados` para structs" + +#: src\idioms/priv-extend.md:59 +#, fuzzy +msgid "" +"`#[non_exhaustive]` only works across crate boundaries.\n" +"Within a crate, the private field method may be used." +msgstr "" +"`#[non_exhaustive]` só funciona além dos limites da caixa.\n" +"Dentro de uma caixa, o método de campo privado pode ser usado." + +#: src\idioms/priv-extend.md:62 +#, fuzzy +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 "" +"Adicionar um campo a uma estrutura é uma alteração compatível com versões " +"anteriores.\n" +"No entanto, se um cliente usar um padrão para desconstruir uma instância " +"struct, ele\n" +"pode nomear todos os campos na estrutura e adicionar um novo quebraria isso\n" +"padrão.\n" +"O cliente pode nomear alguns campos e usar `..` no padrão, caso em que " +"adicionar\n" +"outro campo é compatível com versões anteriores.\n" +"Tornar privado pelo menos um dos campos da estrutura obriga os clientes a " +"usar o último\n" +"forma de padrões, garantindo que a estrutura seja à prova de futuro." + +#: src\idioms/priv-extend.md:71 +#, fuzzy +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 "" +"A desvantagem dessa abordagem é que você pode precisar adicionar um\n" +"campo para a estrutura.\n" +"Você pode usar o tipo `()` para que não haja sobrecarga de tempo de execução " +"e anexar `_` para\n" +"o nome do campo para evitar o aviso de campo não utilizado." + +#: 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 +#, fuzzy +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 "" +"Em `struct`s, `#[non_exhaustive]` permite adicionar campos adicionais de " +"forma inversa\n" +"maneira compatível.\n" +"Também impedirá que os clientes usem o construtor struct, mesmo que todos " +"os\n" +"campos são públicos.\n" +"Isso pode ser útil, mas vale a pena considerar se você _quer_ um campo " +"adicional\n" +"ser encontrado pelos clientes como um erro do compilador em vez de algo que " +"pode ser silenciosamente\n" +"não descoberto." + +#: src\idioms/priv-extend.md:95 +#, fuzzy +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 "" +"`#[non_exhaustive]` também pode ser aplicado a variantes de enumeração.\n" +"Uma variante `#[non_exhaustive]` se comporta da mesma forma que uma " +"estrutura `#[non_exhaustive]`." + +#: src\idioms/priv-extend.md:98 +#, fuzzy +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 "" +"Use isso deliberadamente e com cautela: incrementando a versão principal ao " +"adicionar\n" +"campos ou variantes geralmente é uma opção melhor.\n" +"`#[non_exhaustive]` pode ser apropriado em cenários onde você está modelando " +"um externo\n" +"recurso que pode ficar fora de sincronia com sua biblioteca, mas não é um " +"propósito geral\n" +"ferramenta." + +#: src\idioms/priv-extend.md:104 +#, fuzzy +msgid "### Disadvantages" +msgstr "### Desvantagens" + +#: src\idioms/priv-extend.md:106 +#, fuzzy +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 "" +"`#[non_exhaustive]` pode tornar seu código muito menos ergonômico de usar, " +"especialmente quando\n" +"forçado a lidar com variantes de enumeração desconhecidas.\n" +"Só deve ser usado quando esses tipos de evoluções são necessários **sem**\n" +"incrementando a versão principal." + +#: 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 +#, fuzzy +msgid "" +"- [RFC introducing #[non_exhaustive] attribute for enums and " +"structs](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" +msgstr "" +"- [RFC introduzindo o atributo #[non_exhaustive] para enums e " +"structs](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" + +#: src\idioms/rustdoc-init.md:1 +#, fuzzy +msgid "# Easy doc initialization\r" +msgstr "# Fácil inicialização do documento\r" + +#: src\idioms/rustdoc-init.md:5 +#, fuzzy +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 "" +"Se uma estrutura requer um esforço significativo para inicializar ao " +"escrever documentos, pode ser\r\n" +"mais rápido para agrupar seu exemplo com uma função auxiliar que usa a " +"estrutura como um\r\n" +"argumento." + +#: src\idioms/rustdoc-init.md:9 +#, fuzzy +msgid "## Motivation\r" +msgstr "## Motivação\r" + +#: src\idioms/rustdoc-init.md:11 +#, fuzzy +msgid "" +"Sometimes there is a struct with multiple or complicated parameters and " +"several\r\n" +"methods. Each of these methods should have examples." +msgstr "" +"Às vezes, há uma estrutura com parâmetros múltiplos ou complicados e " +"vários\r\n" +"métodos. Cada um desses métodos deve ter exemplos." + +#: src\idioms/rustdoc-init.md:14 +#, fuzzy +msgid "For example:" +msgstr "Por exemplo:" + +#: 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 +#, fuzzy +msgid "## Example\r" +msgstr "## Exemplo\r" + +#: src\idioms/rustdoc-init.md:47 +#, fuzzy +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 "" +"Em vez de digitar todo esse clichê para criar uma `Conexão` e\r\n" +"`Request`, é mais fácil apenas criar uma função auxiliar de empacotamento " +"que leva\r\n" +"como argumentos:" + +#: 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 +#, fuzzy +msgid "## Advantages\r" +msgstr "## Vantagens\r" + +#: src\idioms/rustdoc-init.md:79 +#, fuzzy +msgid "This is much more concise and avoids repetitive code in examples." +msgstr "Isso é muito mais conciso e evita código repetitivo em exemplos." + +#: src\idioms/rustdoc-init.md:81 +#, fuzzy +msgid "## Disadvantages\r" +msgstr "## Desvantagens\r" + +#: src\idioms/rustdoc-init.md:83 +#, fuzzy +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 "" +"Como o exemplo está em uma função, o código não será testado. Embora ainda " +"seja\r\n" +"verificado para garantir que ele compila ao executar um `teste de carga`. " +"Então esse padrão é\r\n" +"mais útil quando você precisa de `no_run`. Com isso, você não precisa " +"adicionar `no_run`." + +#: src\idioms/rustdoc-init.md:87 +#, fuzzy +msgid "## Discussion\r" +msgstr "## Discussão\r" + +#: src\idioms/rustdoc-init.md:89 +#, fuzzy +msgid "If assertions are not required this pattern works well." +msgstr "Se as asserções não forem necessárias, esse padrão funcionará bem." + +#: src\idioms/rustdoc-init.md:91 +#, fuzzy +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 "" +"Se forem, uma alternativa pode ser criar um método público para criar um " +"auxiliar\r\n" +"instância que é anotada com `#[doc(hidden)]` (para que os usuários não a " +"vejam).\r\n" +"Então este método pode ser chamado dentro do rustdoc porque faz parte do\r\n" +"API pública da caixa." + +#: src\idioms/temporary-mutability.md:1 +#, fuzzy +msgid "# Temporary mutability" +msgstr "# Mutabilidade temporária" + +#: src\idioms/temporary-mutability.md:5 +#, fuzzy +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 "" +"Muitas vezes é necessário preparar e processar alguns dados, mas depois " +"disso os dados são\n" +"apenas inspecionado e nunca modificado. A intenção pode ser tornada " +"explícita redefinindo\n" +"a variável mutável como imutável." + +#: src\idioms/temporary-mutability.md:9 +#, fuzzy +msgid "" +"It can be done either by processing data within a nested block or by " +"redefining\n" +"the variable." +msgstr "" +"Isso pode ser feito processando dados dentro de um bloco aninhado ou " +"redefinindo\n" +"a variável." + +#: src\idioms/temporary-mutability.md:14 +#, fuzzy +msgid "Say, vector must be sorted before usage." +msgstr "Diga, o vetor deve ser classificado antes do uso." + +#: src\idioms/temporary-mutability.md:16 +#, fuzzy +msgid "Using nested block:" +msgstr "Usando bloco aninhado:" + +#: 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 +#, fuzzy +msgid "Using variable rebinding:" +msgstr "Usando religação de variável:" + +#: 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 +#, fuzzy +msgid "" +"Compiler ensures that you don't accidentally mutate data after some point." +msgstr "" +"O compilador garante que você não modifique dados acidentalmente após algum " +"ponto." + +#: src\idioms/temporary-mutability.md:44 +#, fuzzy +msgid "" +"Nested block requires additional indentation of block body.\n" +"One more line to return data from block or redefine variable." +msgstr "" +"O bloco aninhado requer recuo adicional do corpo do bloco.\n" +"Mais uma linha para retornar dados do bloco ou redefinir variável." + +#: src\idioms/return-consumed-arg-on-error.md:1 +#, fuzzy +msgid "# Return consumed argument on error" +msgstr "# Retorna o argumento consumido em caso de erro" + +#: src\idioms/return-consumed-arg-on-error.md:5 +#, fuzzy +msgid "" +"If a fallible function consumes (moves) an argument, return that argument " +"back inside\n" +"an error." +msgstr "" +"Se uma função falível consumir (mover) um argumento, retorne esse argumento " +"para dentro\n" +"um erro." + +#: 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 +#, fuzzy +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 "" +"Em caso de erro, você pode querer tentar alguma forma alternativa ou\n" +"repetir a ação em caso de função não determinística. Mas se o argumento\n" +"é sempre consumido, você é forçado a cloná-lo em todas as chamadas, o que\n" +"não é muito eficiente." + +#: src\idioms/return-consumed-arg-on-error.md:50 +#, fuzzy +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 "" +"A biblioteca padrão usa esta abordagem em, por exemplo, Método " +"`String::from_utf8`.\n" +"Quando dado um vetor que não contém UTF-8 válido, um `FromUtf8Error`\n" +"é devolvido.\n" +"Você pode recuperar o vetor original usando o método " +"`FromUtf8Error::into_bytes`." + +#: src\idioms/return-consumed-arg-on-error.md:57 +#, fuzzy +msgid "Better performance because of moving arguments whenever possible." +msgstr "Melhor desempenho devido a argumentos em movimento sempre que possível." + +#: src\idioms/return-consumed-arg-on-error.md:61 +#, fuzzy +msgid "Slightly more complex error types." +msgstr "Tipos de erro um pouco mais complexos." + +#: src\patterns/index.md:1 +#, fuzzy +msgid "# Design Patterns" +msgstr "# Padrões de design" + +#: src\patterns/index.md:3 +#, fuzzy +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 "" +"[Padrões de design](https://en.wikipedia.org/wiki/Software_design_pattern) " +"são\n" +"“soluções gerais reutilizáveis para um problema que ocorre comumente dentro " +"de um determinado\n" +"contexto no design de software\". Os padrões de design são uma ótima maneira " +"de descrever o\n" +"cultura de uma linguagem de programação. Os padrões de design são muito " +"específicos da linguagem -\n" +"o que é um padrão em um idioma pode ser desnecessário em outro devido a uma\n" +"recurso de linguagem ou impossível de expressar devido a um recurso ausente." + +#: src\patterns/index.md:10 +#, fuzzy +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 "" +"Se usados em excesso, os padrões de projeto podem adicionar complexidade " +"desnecessária aos programas.\n" +"No entanto, eles são uma ótima maneira de compartilhar conhecimentos de " +"nível intermediário e avançado\n" +"sobre uma linguagem de programação." + +#: src\patterns/index.md:16 +#, fuzzy +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 "" +"Rust tem muitos recursos exclusivos. Esses recursos nos dão grande benefício " +"ao remover\n" +"classes inteiras de problemas. Alguns deles também são padrões _exclusivos_ " +"do Rust." + +#: src\patterns/index.md:19 +#, fuzzy +msgid "## YAGNI" +msgstr "## YAGNI" + +#: src\patterns/index.md:21 +#, fuzzy +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 "" +"YAGNI é um acrônimo que significa `You Are not Going to Need It`.\n" +"É um princípio de design de software vital a ser aplicado enquanto você " +"escreve o código." + +#: src\patterns/index.md:24 +#, fuzzy +msgid "> The best code I ever wrote was code I never wrote." +msgstr "> O melhor código que já escrevi foi um código que nunca escrevi." + +#: src\patterns/index.md:26 +#, fuzzy +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 "" +"Se aplicarmos o YAGNI aos padrões de projeto, veremos que os recursos do " +"Rust nos permitem\n" +"jogue fora muitos padrões. Por exemplo, não há necessidade do [padrão de " +"estratégia](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"em Rust porque podemos usar apenas " +"[traits](https://doc.rust-lang.org/book/traits.html)." + +#: src\patterns/behavioural/intro.md:1 +#, fuzzy +msgid "# Behavioural Patterns" +msgstr "# Padrões Comportamentais" + +#: src\patterns/behavioural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" + +#: src\patterns/behavioural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that identify common communication patterns among " +"objects.\n" +"> By doing so, these patterns increase flexibility in carrying out " +"communication." +msgstr "" +"> Padrões de design que identificam padrões comuns de comunicação entre " +"objetos.\n" +"> Ao fazer isso, esses padrões aumentam a flexibilidade na realização da " +"comunicação." + +#: src\patterns/behavioural/command.md:1 +#, fuzzy +msgid "# Command" +msgstr "# Comando" + +#: src\patterns/behavioural/command.md:5 +#, fuzzy +msgid "" +"The basic idea of the Command pattern is to separate out actions into its " +"own\n" +"objects and pass them as parameters." +msgstr "" +"A ideia básica do padrão Command é separar as ações em seu próprio\n" +"objetos e passá-los como parâmetros." + +#: src\patterns/behavioural/command.md:10 +#, fuzzy +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 "" +"Suponha que tenhamos uma sequência de ações ou transações encapsuladas como " +"objetos.\n" +"Queremos que essas ações ou comandos sejam executados ou invocados em alguma " +"ordem posteriormente\n" +"em tempo diferente. Esses comandos também podem ser acionados como resultado " +"de algum evento.\n" +"Por exemplo, quando um usuário pressiona um botão ou na chegada de um pacote " +"de dados.\n" +"Além disso, esses comandos podem ser desfeitos. Isso pode ser útil para\n" +"operações de um editor. Podemos querer armazenar logs de comandos executados " +"para que\n" +"poderíamos reaplicar as alterações mais tarde se o sistema travar." + +#: src\patterns/behavioural/command.md:20 +#, fuzzy +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 "" +"Defina duas operações de banco de dados `create table` e `add field`. Cada " +"um desses\n" +"operações é um comando que sabe como desfazer o comando, por exemplo, `drop " +"table`\n" +"e `remover campo`. Quando um usuário invoca uma operação de migração de " +"banco de dados, cada\n" +"comando é executado na ordem definida e quando o usuário invoca o rollback\n" +"operação, então todo o conjunto de comandos é invocado na ordem inversa." + +#: src\patterns/behavioural/command.md:26 +#, fuzzy +msgid "## Approach: Using trait objects" +msgstr "## Abordagem: Usando objetos de característica" + +#: src\patterns/behavioural/command.md:28 +#, fuzzy +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 "" +"Definimos uma característica comum que encapsula nosso comando com duas " +"operações\n" +"`execute` e `rollback`. Todos os `structs` de comando devem implementar esta " +"característica." + +#: 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 +#, fuzzy +msgid "## Approach: Using function pointers" +msgstr "## Abordagem: Usando ponteiros de função" + +#: src\patterns/behavioural/command.md:97 +#, fuzzy +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 "" +"Poderíamos seguir outra abordagem criando cada comando individual como\n" +"uma função diferente e armazenar ponteiros de função para invocar essas " +"funções mais tarde\n" +"em um momento diferente. Como os ponteiros de função implementam todas as " +"três características `Fn`,\n" +"`FnMut` e `FnOnce`, poderíamos passar e armazenar encerramentos em vez de\n" +"ponteiros de função." + +#: 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 +#, fuzzy +msgid "## Approach: Using `Fn` trait objects" +msgstr "## Abordagem: Usando objetos de característica `Fn`" + +#: src\patterns/behavioural/command.md:152 +#, fuzzy +msgid "" +"Finally, instead of defining a common command trait we could store\n" +"each command implementing the `Fn` trait separately in vectors." +msgstr "" +"Finalmente, em vez de definir um traço de comando comum, poderíamos " +"armazenar\n" +"cada comando implementando o traço `Fn` separadamente em vetores." + +#: 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 +#, fuzzy +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 "" +"Se nossos comandos são pequenos e podem ser definidos como funções ou " +"passados como encerramento\n" +"usar ponteiros de função pode ser preferível, pois não explora\n" +"despacho dinâmico. Mas se nosso comando for uma estrutura inteira com um " +"monte de funções\n" +"e variáveis definidas como módulo separado, então usar objetos de " +"característica seria\n" +"mais adequado. Um caso de aplicação pode ser encontrado em " +"[`actix`](https://actix.rs/),\n" +"que usa objetos trait quando registra uma função de manipulador para rotas.\n" +"No caso de usar objetos de característica `Fn`, podemos criar e usar " +"comandos no mesmo\n" +"maneira como usamos no caso de ponteiros de função." + +#: src\patterns/behavioural/command.md:214 +#, fuzzy +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 "" +"Como desempenho, sempre há uma troca entre desempenho e código\n" +"simplicidade e organização. O despacho estático oferece desempenho mais " +"rápido, enquanto\n" +"o despacho dinâmico fornece flexibilidade quando estruturamos nosso " +"aplicativo." + +#: src\patterns/behavioural/command.md:220 +#, fuzzy +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 "" +"- [Padrão de comando](https://en.wikipedia.org/wiki/Command_pattern)\n" +"\n" +"- [Outro exemplo para o padrão " +"`command`](https://web.archive.org/web/20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" + +#: src\patterns/behavioural/interpreter.md:1 +#, fuzzy +msgid "# Interpreter" +msgstr "# Intérprete" + +#: src\patterns/behavioural/interpreter.md:5 +#, fuzzy +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 "" +"Se um problema ocorre com muita frequência e requer etapas longas e " +"repetitivas para resolver\n" +"isso, então as instâncias do problema podem ser expressas em uma linguagem " +"simples e um\n" +"objeto intérprete poderia resolvê-lo interpretando as frases escritas neste\n" +"linguagem simples." + +#: src\patterns/behavioural/interpreter.md:10 +#, fuzzy +msgid "Basically, for any kind of problems we define:" +msgstr "Basicamente, para qualquer tipo de problema definimos:" + +#: src\patterns/behavioural/interpreter.md:12 +#, fuzzy +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 "" +"- Um [idioma específico do " +"domínio](https://en.wikipedia.org/wiki/Domain-specific_language),\n" +"- Uma gramática para esta linguagem,\n" +"- Um interpretador que resolve as instâncias do problema." + +#: src\patterns/behavioural/interpreter.md:18 +#, fuzzy +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 "" +"Nosso objetivo é traduzir expressões matemáticas simples em expressões " +"pós-fixadas\n" +"(ou [notação polonesa " +"reversa](https://en.wikipedia.org/wiki/Reverse_Polish_notation))\n" +"Para simplificar, nossas expressões consistem em dez dígitos `0`, ..., `9` e " +"dois\n" +"operações `+`, `-`. Por exemplo, a expressão `2 + 4` é traduzida para\n" +"`2 4 +`." + +#: src\patterns/behavioural/interpreter.md:24 +#, fuzzy +msgid "## Context Free Grammar for our problem" +msgstr "## Gramática livre de contexto para o nosso problema" + +#: src\patterns/behavioural/interpreter.md:26 +#, fuzzy +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 "" +"Nossa tarefa é traduzir expressões infixas em pós-fixadas. Vamos definir um " +"contexto\n" +"gramática livre para um conjunto de expressões infixas sobre `0`, ..., `9`, " +"`+` e `-`,\n" +"onde:" + +#: src\patterns/behavioural/interpreter.md:30 +#, fuzzy +msgid "" +"- Terminal symbols: `0`, `...`, `9`, `+`, `-`\n" +"- Non-terminal symbols: `exp`, `term`\n" +"- Start symbol is `exp`\n" +"- And the following are production rules" +msgstr "" +"- Símbolos de terminais: `0`, `...`, `9`, `+`, `-`\n" +"- Símbolos não terminais: `exp`, `term`\n" +"- O símbolo inicial é `exp`\n" +"- E as seguintes são regras de produção" + +#: 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 +#, fuzzy +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 "" +"**NOTA:** Esta gramática deve ser transformada dependendo do que vamos\n" +"fazer com isso. Por exemplo, podemos precisar remover a recursão à esquerda. " +"Para mais\n" +"detalhes, consulte [Compilers: Principles,Techniques, and " +"Tools](https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)\n" +"(também conhecido como Livro do Dragão)." + +#: src\patterns/behavioural/interpreter.md:47 +#, fuzzy +msgid "## Solution" +msgstr "## Solução" + +#: src\patterns/behavioural/interpreter.md:49 +#, fuzzy +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 "" +"Simplesmente implementamos um analisador descendente recursivo. Para " +"simplificar, o código\n" +"entra em pânico quando uma expressão está sintaticamente errada (por exemplo " +"`2-34` ou `2+5-`\n" +"estão errados de acordo com a definição gramatical)." + +#: 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 +#, fuzzy +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 "" +"Pode haver uma percepção errada de que o padrão de projeto Interpreter é " +"sobre design\n" +"gramáticas para linguagens formais e implementação de parsers para essas " +"gramáticas.\n" +"Na verdade, esse padrão é sobre expressar instâncias de problemas de uma " +"forma mais específica.\n" +"maneira e implementando funções/classes/estruturas que resolvem essas " +"instâncias do problema.\n" +"A linguagem Rust tem `macro_rules!` que nos permite definir sintaxe e regras " +"especiais\n" +"sobre como expandir essa sintaxe no código-fonte." + +#: src\patterns/behavioural/interpreter.md:112 +#, fuzzy +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 "" +"No exemplo a seguir, criamos um `macro_rules!` simples que calcula\n" +"[Comprimento euclidiano](https://en.wikipedia.org/wiki/Euclidean_distance) " +"de `n`\n" +"vetores dimensionais. Escrever `norma!(x,1,2)` pode ser mais fácil de " +"expressar e mais\n" +"eficiente do que empacotar `x,1,2` em um `Vec` e chamar uma função de " +"computação\n" +"O comprimento." + +#: 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 +#, fuzzy +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 "" +"- [Padrão de intérprete](https://en.wikipedia.org/wiki/Interpreter_pattern)\n" +"- [Gramática livre de " +"contexto](https://en.wikipedia.org/wiki/Context-free_grammar)\n" +"- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" + +#: src\patterns/behavioural/newtype.md:1 +#, fuzzy +msgid "# Newtype" +msgstr "# Novotipo" + +#: src\patterns/behavioural/newtype.md:3 +#, fuzzy +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 "" +"E se em alguns casos quisermos que um tipo se comporte de maneira semelhante " +"a outro tipo ou\n" +"impor algum comportamento em tempo de compilação ao usar apenas aliases de " +"tipo\n" +"não ser suficiente?" + +#: src\patterns/behavioural/newtype.md:7 +#, fuzzy +msgid "" +"For example, if we want to create a custom `Display` implementation for " +"`String`\n" +"due to security considerations (e.g. passwords)." +msgstr "" +"Por exemplo, se quisermos criar uma implementação `Display` personalizada " +"para `String`\n" +"devido a considerações de segurança (por exemplo, senhas)." + +#: src\patterns/behavioural/newtype.md:10 +#, fuzzy +msgid "" +"For such cases we could use the `Newtype` pattern to provide **type " +"safety**\n" +"and **encapsulation**." +msgstr "" +"Para tais casos, poderíamos usar o padrão `Newtype` para fornecer ** " +"segurança de tipo **\n" +"e **encapsulamento**." + +#: src\patterns/behavioural/newtype.md:15 +#, fuzzy +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 "" +"Use uma estrutura de tupla com um único campo para criar um wrapper opaco " +"para um tipo.\n" +"Isso cria um novo tipo, em vez de um alias para um tipo (itens `type`)." + +#: 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 +#, fuzzy +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 "" +"A principal motivação para newtypes é a abstração. Ele permite que você " +"compartilhe\n" +"detalhes de implementação entre tipos enquanto controla com precisão a " +"interface.\n" +"Usando um newtype em vez de expor o tipo de implementação como parte de um\n" +"API, permite que você altere a implementação de forma compatível com versões " +"anteriores." + +#: src\patterns/behavioural/newtype.md:63 +#, fuzzy +msgid "" +"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give\n" +"distinguishable `Miles` and `Kilometres`." +msgstr "" +"Newtypes podem ser usados para distinguir unidades, por exemplo, agrupando " +"`f64` para dar\n" +"distinguíveis 'Milhas' e 'Quilômetros'." + +#: src\patterns/behavioural/newtype.md:68 +#, fuzzy +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 "" +"Os tipos wrapper e wrapper não são compatíveis (ao contrário de usar\n" +"`type`), então os usuários do newtype nunca irão 'confundir' o wrapper e o " +"wrapper\n" +"tipos." + +#: src\patterns/behavioural/newtype.md:72 +#, fuzzy +msgid "Newtypes are a zero-cost abstraction - there is no runtime overhead." +msgstr "" +"Newtypes são uma abstração de custo zero - não há sobrecarga de tempo de " +"execução." + +#: src\patterns/behavioural/newtype.md:74 +#, fuzzy +msgid "" +"The privacy system ensures that users cannot access the wrapped type (if " +"the\n" +"field is private, which it is by default)." +msgstr "" +"O sistema de privacidade garante que os usuários não possam acessar o tipo " +"encapsulado (se o\n" +"campo é privado, o que é por padrão)." + +#: src\patterns/behavioural/newtype.md:79 +#, fuzzy +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 "" +"A desvantagem de newtypes (especialmente em comparação com aliases de tipo) " +"é que há\n" +"não há suporte de idioma especial. Isso significa que pode haver _muito_ " +"clichê.\n" +"Você precisa de um método 'pass through' para cada método que deseja expor " +"no\n" +"tipo embrulhado e um impl para cada característica que você deseja que " +"também seja implementado para\n" +"o tipo de invólucro." + +#: src\patterns/behavioural/newtype.md:87 +#, fuzzy +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 "" +"Newtypes são muito comuns em código Rust. Unidades de abstração ou " +"representação são as\n" +"usos mais comuns, mas podem ser usados por outros motivos:" + +#: src\patterns/behavioural/newtype.md:90 +#, fuzzy +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 "" +"- funcionalidade restritiva (reduzir as funções expostas ou características " +"implementadas),\n" +"- fazer um tipo com semântica de cópia tem semântica de movimento,\n" +"- abstração ao fornecer um tipo mais concreto e, assim, ocultar os tipos " +"internos,\n" +" por exemplo.," + +#: src\patterns/behavioural/newtype.md:95 +msgid "" +"```rust,ignore\n" +"pub struct Foo(Bar);\n" +"```" +msgstr "" + +#: src\patterns/behavioural/newtype.md:99 +#, fuzzy +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 "" +"Aqui, `Bar` pode ser algum tipo público e genérico e `T1` e `T2` são alguns " +"tipos internos\n" +"tipos. Os usuários do nosso módulo não devem saber que implementamos `Foo` " +"usando um `Bar`,\n" +"mas o que realmente estamos escondendo aqui são os tipos `T1` e `T2`, e como " +"eles são usados\n" +"com 'Barra'." + +#: src\patterns/behavioural/newtype.md:106 +#, fuzzy +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 "" +"- [Tipos avançados no " +"livro](https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety " +"-e-abstração)\n" +"- [Novos tipos em Haskell](https://wiki.haskell.org/Newtype)\n" +"- [aliases de " +"tipo](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), uma caixa para " +"derivar muitos\n" +" traços embutidos em novos tipos.\n" +"- [O padrão Newtype em " +"Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)" + +#: src\patterns/behavioural/RAII.md:1 +#, fuzzy +msgid "# RAII with guards" +msgstr "# RAII com guardas" + +#: src\patterns/behavioural/RAII.md:5 +#, fuzzy +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 "" +"[RAII][wikipedia] significa \"Resource Acquisition is Initialisation\" que é " +"um\n" +"nome terrível. A essência do padrão é que a inicialização do recurso é " +"feita\n" +"no construtor de um objeto e a finalização no destruidor. Esse padrão\n" +"é estendido em Rust usando um objeto RAII como guarda de algum recurso e " +"contando\n" +"no sistema de tipos para garantir que o acesso seja sempre mediado pelo " +"objeto de guarda." + +#: src\patterns/behavioural/RAII.md:13 +#, fuzzy +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 "" +"Mutex guards são o exemplo clássico deste padrão da biblioteca std (este\n" +"é uma versão simplificada da implementação real):" + +#: 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 +#, fuzzy +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 "" +"Onde um recurso deve ser finalizado após o uso, o RAII pode ser usado para " +"fazer isso\n" +"finalização. Se for um erro acessar esse recurso após a finalização, então\n" +"esse padrão pode ser usado para evitar tais erros." + +#: src\patterns/behavioural/RAII.md:80 +#, fuzzy +msgid "" +"Prevents errors where a resource is not finalised and where a resource is " +"used\n" +"after finalisation." +msgstr "" +"Evita erros onde um recurso não é finalizado e onde um recurso é usado\n" +"após a finalização." + +#: src\patterns/behavioural/RAII.md:85 +#, fuzzy +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 "" +"RAII é um padrão útil para garantir que os recursos sejam devidamente " +"desalocados ou\n" +"finalizado. Podemos usar o verificador de empréstimo no Rust para prevenir " +"estaticamente\n" +"erros decorrentes do uso de recursos após a finalização." + +#: src\patterns/behavioural/RAII.md:89 +#, fuzzy +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 "" +"O principal objetivo do verificador de empréstimos é garantir que as " +"referências aos dados não\n" +"sobreviver a esses dados. O padrão de guarda RAII funciona porque o objeto " +"de guarda\n" +"contém uma referência ao recurso subjacente e apenas expõe tal\n" +"referências. A ferrugem garante que o guarda não sobreviva ao recurso " +"subjacente\n" +"e que as referências ao recurso mediado pela guarda não podem sobreviver ao\n" +"guarda. Para ver como isso funciona, é útil examinar a assinatura de " +"`deref`\n" +"sem elisão vitalícia:" + +#: 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 +#, fuzzy +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 "" +"A referência retornada ao recurso tem o mesmo tempo de vida que `self` " +"(`'a`).\n" +"O verificador de empréstimo, portanto, garante que o tempo de vida da " +"referência a `T`\n" +"é mais curto que o tempo de vida de `self`." + +#: src\patterns/behavioural/RAII.md:107 +#, fuzzy +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 "" +"Observe que a implementação de `Deref` não é uma parte essencial desse " +"padrão, apenas torna\n" +"usando o objeto de guarda mais ergonômico. Implementando um método `get` no " +"guarda\n" +"funciona tão bem." + +#: src\patterns/behavioural/RAII.md:113 +#, fuzzy +msgid "[Finalisation in destructors idiom](../../idioms/dtor-finally.md)" +msgstr "[Finalização no idioma dos destruidores](../../idioms/dtor-finally.md)" + +#: src\patterns/behavioural/RAII.md:115 +#, fuzzy +msgid "" +"RAII is a common pattern in C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." +msgstr "" +"RAII é um padrão comum em C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." + +#: src\patterns/behavioural/RAII.md:120 +#, fuzzy +msgid "" +"[Style guide " +"entry](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(currently just a placeholder)." +msgstr "" +"[Entrada do guia de " +"estilo](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(atualmente apenas um espaço reservado)." + +#: src\patterns/behavioural/strategy.md:1 +#, fuzzy +msgid "# Strategy (aka Policy)" +msgstr "# Estratégia (também conhecida como Política)" + +#: src\patterns/behavioural/strategy.md:5 +#, fuzzy +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 "" +"O [padrão de design de " +"estratégia](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"é uma técnica que permite a separação de preocupações.\n" +"Também permite desacoplar módulos de software por meio de [Inversão de " +"dependência](https://en.wikipedia.org/wiki/Dependency_inversion_principle)." + +#: src\patterns/behavioural/strategy.md:9 +#, fuzzy +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 "" +"A ideia básica por trás do padrão Strategy é que, dado um algoritmo " +"resolvendo\n" +"um problema particular, definimos apenas o esqueleto do algoritmo em um " +"resumo\n" +"nível, e separamos a implementação do algoritmo específico em diferentes " +"partes." + +#: src\patterns/behavioural/strategy.md:13 +#, fuzzy +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 "" +"Desta forma, um cliente usando o algoritmo pode escolher uma implementação " +"específica,\n" +"enquanto o fluxo de trabalho do algoritmo geral permanece o mesmo. Em outras " +"palavras, o resumo\n" +"especificação da classe não depende da implementação específica do\n" +"classe derivada, mas a implementação específica deve aderir à especificação " +"abstrata.\n" +"É por isso que chamamos de \"Inversão de Dependência\"." + +#: src\patterns/behavioural/strategy.md:21 +#, fuzzy +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 "" +"Imagine que estamos trabalhando em um projeto que gera relatórios todos os " +"meses.\n" +"Precisamos que os relatórios sejam gerados em diferentes formatos " +"(estratégias), por exemplo,\n" +"nos formatos `JSON` ou `Texto Simples`.\n" +"Mas as coisas variam ao longo do tempo e não sabemos que tipo de exigência " +"podemos obter\n" +"no futuro. Por exemplo, podemos precisar gerar nosso relatório em um formato " +"completamente novo\n" +"formato, ou apenas modifique um dos formatos existentes." + +#: src\patterns/behavioural/strategy.md:30 +#, fuzzy +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 "" +"Neste exemplo, nossas invariantes (ou abstrações) são `Context`, " +"`Formatter`,\n" +"e `Report`, enquanto `Text` e `Json` são nossas estruturas de estratégia. " +"Essas estratégias\n" +"tem que implementar o trait `Formatter`." + +#: 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 +#, fuzzy +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 "" +"A principal vantagem é a separação de interesses. Por exemplo, neste caso " +"`Relatório`\n" +"não sabe nada sobre implementações específicas de `Json` e `Text`,\n" +"considerando que as implementações de saída não se preocupam com a forma " +"como os dados são pré-processados,\n" +"armazenado e obtido. A única coisa que eles precisam saber é o contexto e " +"um\n" +"trait e método para implementar, ou seja, `Formatter` e `run`." + +#: src\patterns/behavioural/strategy.md:106 +#, fuzzy +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 "" +"Para cada estratégia deve ser implementado pelo menos um módulo, então o " +"número de módulos\n" +"aumenta com o número de estratégias. Se houver muitas estratégias para " +"escolher\n" +"então os usuários precisam saber como as estratégias diferem umas das outras." + +#: src\patterns/behavioural/strategy.md:112 +#, fuzzy +msgid "" +"In the previous example all strategies are implemented in a single file.\n" +"Ways of providing different strategies includes:" +msgstr "" +"No exemplo anterior todas as estratégias são implementadas em um único " +"arquivo.\n" +"Formas de fornecer diferentes estratégias incluem:" + +#: src\patterns/behavioural/strategy.md:115 +#, fuzzy +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 "" +"- Tudo em um arquivo (conforme mostrado neste exemplo, semelhante a ser " +"separado como módulos)\n" +"- Separados como módulos, por ex. módulo `formatter::json`, módulo " +"`formatter::text`\n" +"- Use sinalizadores de recursos do compilador, por exemplo recurso `json`, " +"recurso `texto`\n" +"- Separados como caixotes, por ex. caixa `json`, caixa `text`" + +#: src\patterns/behavioural/strategy.md:120 +#, fuzzy +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 "" +"Serde crate é um bom exemplo do padrão `Strategy` em ação. Serde permite\n" +"[customização completa](https://serde.rs/custom-serialization.html) da " +"serialização\n" +"comportamento implementando manualmente as características `Serialize` e " +"`Deserialize` para o nosso\n" +"tipo. Por exemplo, poderíamos facilmente trocar `serde_json` por " +"`serde_cbor` já que eles\n" +"expor métodos semelhantes. Ter isso faz com que o auxiliar crie " +"`serde_transcode` muito\n" +"mais útil e ergonômico." + +#: src\patterns/behavioural/strategy.md:127 +#, fuzzy +msgid "" +"However, we don't need to use traits in order to design this pattern in Rust." +msgstr "" +"No entanto, não precisamos usar traits para projetar esse padrão no Rust." + +#: src\patterns/behavioural/strategy.md:129 +#, fuzzy +msgid "" +"The following toy example demonstrates the idea of the Strategy pattern " +"using Rust\n" +"`closures`:" +msgstr "" +"O exemplo de brinquedo a seguir demonstra a ideia do padrão Strategy usando " +"Rust\n" +"`encerramentos`:" + +#: 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 +#, fuzzy +msgid "In fact, Rust already uses this idea for `Options`'s `map` method:" +msgstr "Na verdade, Rust já usa essa ideia para o método `map` de `Options`:" + +#: 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 +#, fuzzy +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 "" +"- [Padrão de Estratégia](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"- [Injeção de " +"dependência](https://en.wikipedia.org/wiki/Dependency_injection)\n" +"- [Design baseado em " +"políticas](https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design)" + +#: src\patterns/behavioural/visitor.md:1 +#, fuzzy +msgid "# Visitor" +msgstr "# Visitante" + +#: src\patterns/behavioural/visitor.md:5 +#, fuzzy +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 "" +"Um visitante encapsula um algoritmo que opera em uma rede heterogênea\n" +"coleção de objetos. Ele permite que vários algoritmos diferentes sejam " +"escritos\n" +"sobre os mesmos dados sem ter que modificar os dados (ou seus principais\n" +"comportamento)." + +#: src\patterns/behavioural/visitor.md:10 +#, fuzzy +msgid "" +"Furthermore, the visitor pattern allows separating the traversal of\n" +"a collection of objects from the operations performed on each object." +msgstr "" +"Além disso, o padrão do visitante permite separar a travessia de\n" +"uma coleção de objetos das operações executadas em cada objeto." + +#: 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 +#, fuzzy +msgid "" +"One could implement further visitors, for example a type checker, without " +"having\n" +"to modify the AST data." +msgstr "" +"Pode-se implementar mais visitantes, por exemplo, um verificador de tipo, " +"sem ter\n" +"para modificar os dados AST." + +#: src\patterns/behavioural/visitor.md:74 +#, fuzzy +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 "" +"O padrão do visitante é útil em qualquer lugar que você deseja aplicar um " +"algoritmo para\n" +"dados heterogêneos. Se os dados forem homogêneos, você pode usar um padrão " +"do tipo iterador.\n" +"O uso de um objeto de visitante (em vez de uma abordagem funcional) permite " +"que o visitante\n" +"ser stateful e, assim, comunicar informações entre os nós." + +#: src\patterns/behavioural/visitor.md:81 +#, fuzzy +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 "" +"É comum que os métodos `visit_*` retornem void (em oposição ao método\n" +"exemplo). Nesse caso, é possível fatorar o código de travessia e " +"compartilhar\n" +"entre algoritmos (e também para fornecer métodos padrão noop). Em Ferrugem, " +"o\n" +"A maneira comum de fazer isso é fornecer funções `walk_*` para cada dado. " +"Para\n" +"exemplo," + +#: 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 +#, fuzzy +msgid "" +"In other languages (e.g., Java) it is common for data to have an `accept` " +"method\n" +"which performs the same duty." +msgstr "" +"Em outras linguagens (por exemplo, Java) é comum que os dados tenham um " +"método `accept`\n" +"que cumpre a mesma função." + +#: src\patterns/behavioural/visitor.md:108 +#, fuzzy +msgid "The visitor pattern is a common pattern in most OO languages." +msgstr "" +"O padrão de visitante é um padrão comum na maioria das linguagens orientadas " +"a objetos." + +#: src\patterns/behavioural/visitor.md:110 +#, fuzzy +msgid "[Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern)" +msgstr "[Artigo da Wikipédia](https://en.wikipedia.org/wiki/Visitor_pattern)" + +#: src\patterns/behavioural/visitor.md:112 +#, fuzzy +msgid "" +"The [fold](../creational/fold.md) pattern is similar to visitor but " +"produces\n" +"a new version of the visited data structure." +msgstr "" +"O padrão [fold](../creational/fold.md) é semelhante ao do visitante, mas " +"produz\n" +"uma nova versão da estrutura de dados visitada." + +#: src\patterns/creational/intro.md:1 +#, fuzzy +msgid "# Creational Patterns" +msgstr "# Padrões Criacionais" + +#: src\patterns/creational/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" + +#: src\patterns/creational/intro.md:5 +#, fuzzy +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 "" +"> Padrões de design que lidam com mecanismos de criação de objetos, tentando " +"criar objetos\n" +"> de forma adequada à situação. A forma básica de criação de objetos " +"poderia\n" +"> resultar em problemas de projeto ou em complexidade adicional ao projeto. " +"design criacional\n" +"> os padrões resolvem esse problema controlando de alguma forma a criação " +"desse objeto." + +#: src\patterns/creational/builder.md:1 +#, fuzzy +msgid "# Builder" +msgstr "# Construtor" + +#: src\patterns/creational/builder.md:5 +#, fuzzy +msgid "Construct an object with calls to a builder helper." +msgstr "Construa um objeto com chamadas para um auxiliar de construtor." + +#: 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 +#, fuzzy +msgid "" +"Useful when you would otherwise require many constructors or where\n" +"construction has side effects." +msgstr "" +"Útil quando você precisaria de muitos construtores ou onde\n" +"construção tem efeitos colaterais." + +#: src\patterns/creational/builder.md:70 +#, fuzzy +msgid "Separates methods for building from other methods." +msgstr "Separa métodos para construção de outros métodos." + +#: src\patterns/creational/builder.md:72 +#, fuzzy +msgid "Prevents proliferation of constructors." +msgstr "Previne a proliferação de construtores." + +#: src\patterns/creational/builder.md:74 +#, fuzzy +msgid "" +"Can be used for one-liner initialisation as well as more complex " +"construction." +msgstr "" +"Pode ser usado para inicialização de uma linha, bem como construções mais " +"complexas." + +#: src\patterns/creational/builder.md:78 +#, fuzzy +msgid "" +"More complex than creating a struct object directly, or a simple " +"constructor\n" +"function." +msgstr "" +"Mais complexo do que criar um objeto struct diretamente ou um construtor " +"simples\n" +"função." + +#: src\patterns/creational/builder.md:83 +#, fuzzy +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 "" +"Esse padrão é visto com mais frequência em Rust (e para objetos mais " +"simples) do que em\n" +"muitas outras linguagens porque Rust não tem sobrecarga. Como você só pode " +"ter um\n" +"método único com um determinado nome, ter vários construtores é menos " +"agradável em\n" +"Rust do que em C++, Java ou outros." + +#: src\patterns/creational/builder.md:88 +#, fuzzy +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 "" +"Esse padrão é frequentemente usado onde o objeto construtor é útil por si " +"só,\n" +"em vez de ser apenas um construtor. Por exemplo, veja\n" +"[`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html)\n" +"é um construtor para " +"[`Child`](https://doc.rust-lang.org/std/process/struct.Child.html)\n" +"(um processo). Nesses casos, o padrão de nomenclatura `T` e `TBuilder` não é " +"usado." + +#: src\patterns/creational/builder.md:94 +#, fuzzy +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 "" +"O exemplo pega e retorna o construtor por valor. Muitas vezes é mais " +"ergonômico\n" +"(e mais eficiente) para obter e retornar o construtor como uma referência " +"mutável. O\n" +"o verificador de empréstimo faz isso funcionar naturalmente. Esta abordagem " +"tem a vantagem de\n" +"pode-se escrever código como" + +#: 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 +#, fuzzy +msgid "as well as the `FooBuilder::new().a().b().build()` style." +msgstr "assim como o estilo `FooBuilder::new().a().b().build()`." + +#: src\patterns/creational/builder.md:110 +#, fuzzy +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 "" +"- [Descrição no guia de " +"estilo](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), uma caixa para " +"automaticamente\n" +" implementando esse padrão enquanto evita o clichê.\n" +"- [Padrão construtor](../../idioms/ctor.md) para quando a construção é mais " +"simples.\n" +"- [Padrão do construtor " +"(wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern)\n" +"- [Construção de valores " +"complexos](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder)" + +#: src\patterns/creational/fold.md:1 +#, fuzzy +msgid "# Fold" +msgstr "# Dobrar" + +#: src\patterns/creational/fold.md:5 +#, fuzzy +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 "" +"Execute um algoritmo sobre cada item em uma coleção de dados para criar um " +"novo item,\n" +"criando assim uma coleção totalmente nova." + +#: src\patterns/creational/fold.md:8 +#, fuzzy +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 "" +"A etimologia aqui não é clara para mim. Os termos 'dobrar' e 'pasta' são " +"usados\n" +"no compilador Rust, embora me pareça mais um mapa do que um\n" +"dobrar no sentido usual. Veja a discussão abaixo para mais detalhes." + +#: 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 +#, fuzzy +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 "" +"O resultado da execução do `Renamer` em um AST é um novo AST idêntico ao " +"antigo\n" +"um, mas com todos os nomes alterados para `foo`. Uma pasta da vida real pode " +"ter alguns\n" +"estado preservado entre nós na própria estrutura." + +#: src\patterns/creational/fold.md:69 +#, fuzzy +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 "" +"Uma pasta também pode ser definida para mapear uma estrutura de dados para " +"outra (mas\n" +"geralmente semelhante) estrutura de dados. Por exemplo, poderíamos dobrar um " +"AST em um HIR\n" +"árvore (HIR significa representação intermediária de alto nível)." + +#: src\patterns/creational/fold.md:75 +#, fuzzy +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 "" +"É comum querer mapear uma estrutura de dados realizando alguma operação em\n" +"cada nó da estrutura. Para operações simples em estruturas de dados " +"simples,\n" +"isso pode ser feito usando `Iterator::map`. Para operações mais complexas, " +"talvez\n" +"onde nós anteriores podem afetar a operação em nós posteriores, ou onde a " +"iteração\n" +"sobre a estrutura de dados não é trivial, usar o padrão de dobra é mais\n" +"apropriado." + +#: src\patterns/creational/fold.md:82 +#, fuzzy +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 "" +"Assim como o padrão Visitor, o padrão Fold nos permite separar a travessia " +"de um\n" +"estrutura de dados das operações realizadas para cada nó." + +#: src\patterns/creational/fold.md:87 +#, fuzzy +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 "" +"Mapear estruturas de dados dessa maneira é comum em linguagens funcionais. " +"Eu não\n" +"idiomas, seria mais comum alterar a estrutura de dados no local. O\n" +"abordagem 'funcional' é comum em Rust, principalmente devido à preferência " +"por\n" +"imutabilidade. Usar novas estruturas de dados, em vez de modificar " +"estruturas antigas, torna\n" +"Raciocinar sobre o código é mais fácil na maioria das circunstâncias." + +#: src\patterns/creational/fold.md:93 +#, fuzzy +msgid "" +"The trade-off between efficiency and reusability can be tweaked by changing " +"how\n" +"nodes are accepted by the `fold_*` methods." +msgstr "" +"A compensação entre eficiência e reutilização pode ser ajustada alterando a " +"forma como\n" +"nós são aceitos pelos métodos `fold_*`." + +#: src\patterns/creational/fold.md:96 +#, fuzzy +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 "" +"No exemplo acima, operamos em ponteiros `Box`. Uma vez que estes possuem " +"seus dados\n" +"exclusivamente, a cópia original da estrutura de dados não pode ser " +"reutilizada. No\n" +"por outro lado, se um nó não for alterado, reutilizá-lo é muito eficiente." + +#: 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 +#, fuzzy +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 "" +"Usar um ponteiro de contagem de referência oferece o melhor dos dois mundos " +"- podemos reutilizar\n" +"a estrutura de dados original e não precisamos clonar nós inalterados. No " +"entanto,\n" +"eles são menos ergonômicos de usar e significam que as estruturas de dados " +"não podem ser\n" +"mutável." + +#: src\patterns/creational/fold.md:111 +#, fuzzy +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 "" +"Os iteradores têm um método `fold`, no entanto, isso dobra uma estrutura de " +"dados em um\n" +"valor, em vez de em uma nova estrutura de dados. O `map` de um iterador é " +"mais parecido com\n" +"este padrão de dobra." + +#: src\patterns/creational/fold.md:115 +#, fuzzy +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 "" +"Em outras linguagens, fold é geralmente usado no sentido dos iteradores do " +"Rust,\n" +"em vez deste padrão. Algumas linguagens funcionais têm construções poderosas " +"para\n" +"realizando mapas flexíveis sobre estruturas de dados." + +#: src\patterns/creational/fold.md:119 +#, fuzzy +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 "" +"O padrão [visitor](../behavioural/visitor.md) está intimamente relacionado à " +"dobra.\n" +"Eles compartilham o conceito de percorrer uma estrutura de dados realizando " +"uma operação em\n" +"cada nó. No entanto, o visitante não cria uma nova estrutura de dados nem " +"consome\n" +"o antigo." + +#: src\patterns/structural/intro.md:1 +#, fuzzy +msgid "# Structural Patterns" +msgstr "# Padrões Estruturais" + +#: src\patterns/structural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" + +#: src\patterns/structural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that ease the design by identifying a simple way to " +"realize relationships\n" +"> among entities." +msgstr "" +"> Padrões de design que facilitam o design identificando uma maneira simples " +"de realizar relacionamentos\n" +"> entre entidades." + +#: src\patterns/structural/compose-structs.md:1 +#, fuzzy +msgid "# Compose structs together for better borrowing" +msgstr "# Compor estruturas juntas para melhor empréstimo" + +#: src\patterns/structural/compose-structs.md:3 +#, fuzzy +msgid "TODO - this is not a very snappy name" +msgstr "TODO - este não é um nome muito rápido" + +#: src\patterns/structural/compose-structs.md:7 +#, fuzzy +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 "" +"Às vezes, uma estrutura grande causará problemas com o verificador de " +"empréstimo - embora\n" +"campos podem ser emprestados de forma independente, às vezes toda a " +"estrutura acaba sendo\n" +"usados de uma só vez, impedindo outros usos. Uma solução pode ser decompor a " +"estrutura\n" +"em várias estruturas menores. Em seguida, componha-os juntos no original\n" +"struct. Em seguida, cada struct pode ser emprestado separadamente e ter mais " +"flexibilidade\n" +"comportamento." + +#: src\patterns/structural/compose-structs.md:14 +#, fuzzy +msgid "" +"This will often lead to a better design in other ways: applying this design\n" +"pattern often reveals smaller units of functionality." +msgstr "" +"Isso geralmente leva a um design melhor de outras maneiras: aplicando esse " +"design\n" +"padrão geralmente revela unidades menores de funcionalidade." + +#: src\patterns/structural/compose-structs.md:19 +#, fuzzy +msgid "" +"Here is a contrived example of where the borrow checker foils us in our plan " +"to\n" +"use a struct:" +msgstr "" +"Aqui está um exemplo forjado de onde o verificador de empréstimos nos " +"frustra em nosso plano de\n" +"use uma estrutura:" + +#: 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 +#, fuzzy +msgid "" +"We can apply this design pattern and refactor `A` into two smaller structs, " +"thus\n" +"solving the borrow checking issue:" +msgstr "" +"Podemos aplicar esse padrão de design e refatorar `A` em duas estruturas " +"menores, assim\n" +"resolvendo o problema de verificação de empréstimo:" + +#: 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 +#, fuzzy +msgid "TODO Why and where you should use the pattern" +msgstr "TODO Por que e onde você deve usar o padrão" + +#: src\patterns/structural/compose-structs.md:77 +#, fuzzy +msgid "Lets you work around limitations in the borrow checker." +msgstr "Permite contornar as limitações no verificador de empréstimos." + +#: src\patterns/structural/compose-structs.md:79 +#, fuzzy +msgid "Often produces a better design." +msgstr "Muitas vezes produz um design melhor." + +#: src\patterns/structural/compose-structs.md:83 +#, fuzzy +msgid "Leads to more verbose code." +msgstr "Leva a um código mais detalhado." + +#: src\patterns/structural/compose-structs.md:85 +#, fuzzy +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 "" +"Às vezes, as estruturas menores não são boas abstrações e, portanto, " +"acabamos com\n" +"um projeto pior. Isso é provavelmente um 'cheiro de código', indicando que o " +"programa\n" +"deve ser refatorado de alguma forma." + +#: src\patterns/structural/compose-structs.md:91 +#, fuzzy +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 "" +"Esse padrão não é necessário em idiomas que não possuem um verificador de " +"empréstimo, então\n" +"nesse sentido, é exclusivo do Rust. No entanto, fazer unidades menores de " +"funcionalidade\n" +"muitas vezes leva a um código mais limpo: um princípio de software " +"amplamente reconhecido\n" +"engenharia, independente do idioma." + +#: src\patterns/structural/compose-structs.md:96 +#, fuzzy +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 "" +"Esse padrão depende do verificador de empréstimo do Rust para poder " +"emprestar campos\n" +"independentemente um do outro. No exemplo, o verificador de empréstimo sabe " +"que `a.b`\n" +"e `a.c` são distintos e podem ser emprestados independentemente, ele não " +"tenta\n" +"pegue emprestado todo `a`, o que tornaria esse padrão inútil." + +#: src\patterns/structural/small-crates.md:1 +#, fuzzy +msgid "# Prefer small crates" +msgstr "# Prefira caixotes pequenos" + +#: src\patterns/structural/small-crates.md:5 +#, fuzzy +msgid "Prefer small crates that do one thing well." +msgstr "Prefira caixas pequenas que façam uma coisa bem." + +#: src\patterns/structural/small-crates.md:7 +#, fuzzy +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 "" +"Cargo e crates.io facilitam a adição de bibliotecas de terceiros, muito mais " +"do que\n" +"digamos em C ou C++. Além disso, como os pacotes no crates.io não podem ser " +"editados ou removidos\n" +"após a publicação, qualquer compilação que funcione agora deve continuar " +"funcionando no futuro.\n" +"Devemos aproveitar essas ferramentas e usar dependências menores e mais " +"refinadas." + +#: src\patterns/structural/small-crates.md:14 +#, fuzzy +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 "" +"- Caixas pequenas são mais fáceis de entender e incentivam um código mais " +"modular.\n" +"- As caixas permitem a reutilização de código entre projetos.\n" +" Por exemplo, a caixa `url` foi desenvolvida como parte do mecanismo do " +"navegador Servo,\n" +" mas desde então encontrou amplo uso fora do projeto.\n" +"- Desde a unidade de compilação\n" +" de Rust é a caixa, dividir um projeto em várias caixas pode permitir mais\n" +" o código a ser construído em paralelo." + +#: src\patterns/structural/small-crates.md:24 +#, fuzzy +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 "" +"- Isso pode levar ao \"inferno da dependência\", quando um projeto depende " +"de vários\n" +" versões de uma caixa ao mesmo tempo. Por exemplo, a caixa `url` tem ambas " +"as versões\n" +" 1,0 e 0,5. Como o `Url` de `url:1.0` e o `Url` de `url:0.5` são\n" +" tipos diferentes, um cliente HTTP que usa `url:0.5` não aceitaria valores " +"`Url`\n" +" de um web scraper que usa `url:1.0`.\n" +"- Pacotes em crates.io não são selecionados. Uma caixa pode estar mal " +"escrita, ter\n" +" documentação inútil ou totalmente malicioso.\n" +"- Duas caixas pequenas podem ser menos otimizadas do que uma grande, pois o " +"compilador\n" +" não executa otimização de tempo de link (LTO) por padrão." + +#: src\patterns/structural/small-crates.md:36 +#, fuzzy +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions\n" +"for converting `&T` to `&[T]`." +msgstr "" +"A caixa [`ref_slice`](https://crates.io/crates/ref_slice) fornece funções\n" +"para converter `&T` em `&[T]`." + +#: src\patterns/structural/small-crates.md:39 +#, fuzzy +msgid "" +"The [`url`](https://crates.io/crates/url) crate provides tools for working " +"with\n" +"URLs." +msgstr "" +"A caixa [`url`](https://crates.io/crates/url) fornece ferramentas para " +"trabalhar com\n" +"URLs." + +#: src\patterns/structural/small-crates.md:42 +#, fuzzy +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 "" +"A caixa [`num_cpus`](https://crates.io/crates/num_cpus) fornece uma função " +"para\n" +"consultar o número de CPUs em uma máquina." + +#: src\patterns/structural/small-crates.md:47 +#, fuzzy +msgid "- [crates.io: The Rust community crate host](https://crates.io/)" +msgstr "- [crates.io: o host de caixas da comunidade Rust](https://crates.io/)" + +#: src\patterns/structural/unsafe-mods.md:1 +#, fuzzy +msgid "# Contain unsafety in small modules" +msgstr "# Conter a insegurança em pequenos módulos" + +#: src\patterns/structural/unsafe-mods.md:5 +#, fuzzy +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 "" +"Se você tiver um código `inseguro`, crie o menor módulo possível que possa " +"suportar\n" +"as invariantes necessárias para construir uma interface segura mínima sobre " +"a insegurança. Embutir\n" +"isso em um módulo maior que contém apenas código seguro e apresenta um " +"design ergonômico\n" +"interface. Observe que o módulo externo pode conter funções e métodos " +"inseguros\n" +"que chamam diretamente para o código inseguro. Os usuários podem usar isso " +"para obter benefícios de velocidade." + +#: src\patterns/structural/unsafe-mods.md:13 +#, fuzzy +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 "" +"- Isso restringe o código inseguro que deve ser auditado\n" +"- Escrever o módulo externo é muito mais fácil, pois você pode contar com as " +"garantias\n" +" do módulo interno" + +#: src\patterns/structural/unsafe-mods.md:19 +#, fuzzy +msgid "" +"- Sometimes, it may be hard to find a suitable interface.\n" +"- The abstraction may introduce inefficiencies." +msgstr "" +"- Às vezes, pode ser difícil encontrar uma interface adequada.\n" +"- A abstração pode introduzir ineficiências." + +#: src\patterns/structural/unsafe-mods.md:24 +#, fuzzy +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 "" +"- A caixa [`toolshed`](https://docs.rs/toolshed) contém suas operações " +"inseguras\n" +" em submódulos, apresentando uma interface segura aos usuários.\n" +"- A classe `String` de `std` é um wrapper sobre `Vec` com a invariante " +"adicionada\n" +" que o conteúdo deve ser UTF-8 válido. As operações em `String` garantem " +"isso\n" +" comportamento.\n" +" No entanto, os usuários têm a opção de usar um método `inseguro` para " +"criar uma `String`,\n" +" neste caso, cabe a eles o ônus de garantir a validade do conteúdo." + +#: src\patterns/structural/unsafe-mods.md:34 +#, fuzzy +msgid "" +"- [Ralf Jung's Blog about invariants in unsafe " +"code](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" +msgstr "" +"- [Blog de Ralf Jung sobre invariantes em código " +"inseguro](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" + +#: src\patterns/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Patterns" +msgstr "# Padrões FFI" + +#: src\patterns/ffi/intro.md:3 +#, fuzzy +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 "" +"Escrever código FFI é um curso completo em si.\n" +"No entanto, existem vários idiomas aqui que podem atuar como ponteiros e " +"evitar armadilhas\n" +"para usuários inexperientes de Rust inseguro." + +#: src\patterns/ffi/intro.md:7 +#, fuzzy +msgid "This section contains design patterns that may be useful when doing FFI." +msgstr "Esta seção contém padrões de projeto que podem ser úteis ao fazer FFI." + +#: src\patterns/ffi/intro.md:9 +#, fuzzy +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 "" +"1. Design de [API baseada em objeto](./export.md) que possui boas " +"características de segurança de memória,\n" +" e um limite claro do que é seguro e do que não é seguro\n" +"\n" +"2. [Digite Consolidação em Wrappers](./wrappers.md) - agrupe vários tipos de " +"Rust\n" +" juntos em um \"objeto\" opaco" + +#: src\patterns/ffi/export.md:1 +#, fuzzy +msgid "# Object-Based APIs" +msgstr "# APIs baseadas em objetos" + +#: src\patterns/ffi/export.md:5 +#, fuzzy +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 "" +"Ao projetar APIs em Rust expostas a outras linguagens, existem algumas\n" +"princípios de design importantes que são contrários ao design normal da Rust " +"API:" + +#: src\patterns/ffi/export.md:8 +#, fuzzy +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 "" +"1. Todos os tipos encapsulados devem ser _propriedade_ da Rust, " +"_gerenciados_ pelo usuário,\n" +" e _opaco_.\n" +"2. Todos os tipos de dados transacionais devem ser _propriedade_ do usuário " +"e _transparentes_.\n" +"3. Todo o comportamento da biblioteca deve ser funções agindo sobre tipos " +"encapsulados.\n" +"4. Todo o comportamento da biblioteca deve ser encapsulado em tipos não " +"baseados em estrutura,\n" +" mas _proveniência/tempo de vida_." + +#: src\patterns/ffi/export.md:17 +#, fuzzy +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 "" +"Rust possui suporte FFI integrado para outros idiomas.\n" +"Ele faz isso fornecendo uma maneira para os autores de caixas fornecerem " +"APIs compatíveis com C\n" +"através de diferentes ABIs (embora isso não seja importante para esta " +"prática)." + +#: src\patterns/ffi/export.md:21 +#, fuzzy +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 "" +"O Rust FFI bem projetado segue os princípios de design da API C, ao mesmo " +"tempo em que compromete o\n" +"projete em Rust o mínimo possível. Existem três objetivos com qualquer API " +"estrangeira:" + +#: src\patterns/ffi/export.md:24 +#, fuzzy +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 "" +"1. Facilite o uso no idioma de destino.\n" +"2. Evite o máximo possível a API ditando a insegurança interna no lado da " +"Rust.\n" +"3. Mantenha o potencial de insegurança de memória e \"comportamento " +"indefinido\" Rust como pequeno\n" +" que possível." + +#: src\patterns/ffi/export.md:29 +#, fuzzy +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 "" +"O código Rust deve confiar na segurança da memória do idioma estrangeiro " +"além de um certo\n" +"apontar. No entanto, cada pedaço de código `inseguro` no lado do Rust é uma " +"oportunidade para\n" +"bugs, ou para exacerbar `comportamento indefinido`." + +#: src\patterns/ffi/export.md:33 +#, fuzzy +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 "" +"Por exemplo, se a proveniência de um ponteiro estiver errada, isso pode ser " +"uma falha de segmentação devido a\n" +"acesso inválido à memória. Mas se for manipulado por código inseguro, pode " +"tornar-se\n" +"corrupção total da pilha." + +#: src\patterns/ffi/export.md:37 +#, fuzzy +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 "" +"O design da API baseada em objeto permite escrever shims com boa segurança " +"de memória\n" +"características e um limite claro do que é seguro e do que é 'inseguro'." + +#: src\patterns/ffi/export.md:42 +#, fuzzy +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 "" +"O padrão POSIX define a API para acessar um banco de dados on-file, " +"conhecido como " +"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h) " +".\n" +"É um excelente exemplo de uma API \"baseada em objeto\"." + +#: src\patterns/ffi/export.md:45 +#, fuzzy +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 "" +"Aqui está a definição em C, que deve ser fácil de ler para aqueles\n" +"envolvidos no FFI. O comentário abaixo deve ajudar a explicá-lo para aqueles " +"que\n" +"perca as sutilezas." + +#: 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 +#, fuzzy +msgid "This API defines two types: `DBM` and `datum`." +msgstr "Esta API define dois tipos: `DBM` e `datum`." + +#: src\patterns/ffi/export.md:66 +#, fuzzy +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 "" +"O tipo `DBM` foi chamado de tipo \"encapsulado\" acima.\n" +"Ele é projetado para conter o estado interno e atua como um ponto de entrada " +"para o\n" +"comportamento da biblioteca." + +#: src\patterns/ffi/export.md:70 +#, fuzzy +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 "" +"É completamente opaco para o usuário, que não pode criar um `DBM` por conta " +"própria, pois\n" +"eles não sabem seu tamanho ou layout. Em vez disso, eles devem chamar " +"`dbm_open`, e isso\n" +"apenas dá a eles _um ponteiro para um_." + +#: src\patterns/ffi/export.md:74 +#, fuzzy +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 "" +"Isso significa que todos os `DBM`s são \"propriedade\" da biblioteca no " +"sentido Rust.\n" +"O estado interno de tamanho desconhecido é mantido na memória controlada " +"pela biblioteca,\n" +"não o usuário. O usuário só pode gerenciar seu ciclo de vida com 'abrir' e " +"'fechar',\n" +"e executar operações nele com as outras funções." + +#: src\patterns/ffi/export.md:79 +#, fuzzy +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 "" +"O tipo `datum` foi chamado de tipo \"transacional\" acima.\n" +"Ele é projetado para facilitar a troca de informações entre a biblioteca e " +"os\n" +"seu usuário." + +#: src\patterns/ffi/export.md:83 +#, fuzzy +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 "" +"O banco de dados é projetado para armazenar \"dados não estruturados\", sem " +"comprimento pré-definido\n" +"ou significado. Como resultado, o `datum` é o equivalente em C de uma fatia " +"Rust: um monte\n" +"de bytes e uma contagem de quantos existem. A principal diferença é que " +"existe\n" +"nenhuma informação de tipo, que é o que `void` indica." + +#: src\patterns/ffi/export.md:88 +#, fuzzy +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 "" +"Tenha em mente que este cabeçalho foi escrito do ponto de vista da " +"biblioteca.\n" +"O usuário provavelmente tem algum tipo que está usando, que tem um tamanho " +"conhecido.\n" +"Mas a biblioteca não se importa, e pelas regras do C casting, qualquer tipo " +"por trás de um\n" +"ponteiro pode ser convertido em `void`." + +#: src\patterns/ffi/export.md:93 +#, fuzzy +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 "" +"Conforme observado anteriormente, esse tipo é _transparent_ para o usuário. " +"Mas também, este tipo é\n" +"_propriedade_ do usuário.\n" +"Isso tem ramificações sutis, devido ao ponteiro dentro dele.\n" +"A questão é: a quem pertence a memória para a qual o ponteiro aponta?" + +#: src\patterns/ffi/export.md:98 +#, fuzzy +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 "" +"A resposta para a melhor segurança de memória é \"o usuário\".\n" +"Mas em casos como recuperar um valor, o usuário não sabe como alocar\n" +"corretamente (já que eles não sabem quanto tempo é o valor). Neste caso, a " +"biblioteca\n" +"espera-se que o código use o heap ao qual o usuário tem acesso -- como a " +"biblioteca C\n" +"`malloc` e `free` -- e então _transferir propriedade_ no sentido Rust." + +#: src\patterns/ffi/export.md:104 +#, fuzzy +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 "" +"Tudo isso pode parecer especulativo, mas é isso que um ponteiro significa em " +"C.\n" +"Significa a mesma coisa que Rust: \"tempo de vida definido pelo usuário\".\n" +"O usuário da biblioteca precisa ler a documentação para utilizá-la " +"corretamente.\n" +"Dito isso, há algumas decisões que têm menos ou mais consequências se os " +"usuários\n" +"faça errado. Minimizá-los é o objetivo desta melhor prática, e a chave\n" +"é _transferir a propriedade de tudo que é transparente_." + +#: src\patterns/ffi/export.md:113 +#, fuzzy +msgid "" +"This minimizes the number of memory safety guarantees the user must uphold " +"to a\n" +"relatively small number:" +msgstr "" +"Isso minimiza o número de garantias de segurança de memória que o usuário " +"deve manter a um\n" +"número relativamente pequeno:" + +#: src\patterns/ffi/export.md:116 +#, fuzzy +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 "" +"1. Não chame nenhuma função com um ponteiro não retornado por `dbm_open` " +"(inválido\n" +" acesso ou corrupção).\n" +"2. Não chame nenhuma função em um ponteiro depois de fechar (use depois de " +"liberar).\n" +"3. O `dptr` em qualquer `datum` deve ser `NULL` ou apontar para uma parte " +"válida da memória\n" +" no comprimento anunciado." + +#: src\patterns/ffi/export.md:122 +#, fuzzy +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 "" +"Além disso, evita muitos problemas de proveniência do ponteiro.\n" +"Para entender o porquê, vamos considerar uma alternativa com alguma " +"profundidade: iteração de chave." + +#: src\patterns/ffi/export.md:125 +#, fuzzy +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 "" +"Rust é bem conhecido por seus iteradores.\n" +"Ao implementar um, o programador cria um tipo separado com um tempo de vida " +"limitado\n" +"ao seu proprietário e implementa a característica `Iterator`." + +#: src\patterns/ffi/export.md:129 +#, fuzzy +msgid "Here is how iteration would be done in Rust for `DBM`:" +msgstr "Aqui está como a iteração seria feita em Rust para `DBM`:" + +#: 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 +#, fuzzy +msgid "" +"This is clean, idiomatic, and safe. thanks to Rust's guarantees.\n" +"However, consider what a straightforward API translation would look like:" +msgstr "" +"Isso é limpo, idiomático e seguro. graças às garantias de Rust.\n" +"No entanto, considere como seria uma tradução direta da API:" + +#: 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 +#, fuzzy +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 "" +"Essa API perde uma informação importante: o tempo de vida do iterador não " +"deve\n" +"exceder o tempo de vida do objeto `Dbm` que o possui. Um usuário da " +"biblioteca pode\n" +"usá-lo de uma maneira que faça com que o iterador sobreviva aos dados em que " +"está iterando,\n" +"resultando na leitura de memória não inicializada." + +#: src\patterns/ffi/export.md:173 +#, fuzzy +msgid "" +"This example written in C contains a bug that will be explained afterwards:" +msgstr "Este exemplo escrito em C contém um bug que será explicado a seguir:" + +#: 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 +#, fuzzy +msgid "" +"This bug is a classic. Here's what happens when the iterator returns the\n" +"end-of-iteration marker:" +msgstr "" +"Este erro é um clássico. Aqui está o que acontece quando o iterador retorna " +"o\n" +"marcador de fim de iteração:" + +#: src\patterns/ffi/export.md:205 +#, fuzzy +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 "" +"1. A condição do loop define `l` como zero e entra no loop porque `0 >= 0`.\n" +"2. O comprimento é incrementado, neste caso por zero.\n" +"3. A instrução if é verdadeira, então o banco de dados está fechado. Deve " +"haver uma pausa\n" +" declaração aqui.\n" +"4. A condição do loop é executada novamente, causando uma chamada `next` no " +"objeto fechado." + +#: src\patterns/ffi/export.md:211 +#, fuzzy +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 "" +"A pior parte desse bug?\n" +"Se a implementação do Rust for cuidadosa, esse código funcionará na maioria " +"das vezes!\n" +"Se a memória para o objeto `Dbm` não for reutilizada imediatamente, uma " +"verificação interna\n" +"quase certamente falhará, resultando no iterador retornando um `-1` " +"indicando\n" +"um erro. Mas, ocasionalmente, causará uma falha de segmentação ou, pior " +"ainda,\n" +"corrupção de memória sem sentido!" + +#: src\patterns/ffi/export.md:218 +#, fuzzy +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 "" +"Nada disso pode ser evitado por Rust.\n" +"De sua perspectiva, ele colocou esses objetos em sua pilha, retornou " +"ponteiros para eles,\n" +"e desistiram do controle de suas vidas. O código C simplesmente deve \"jogar " +"bem\"." + +#: src\patterns/ffi/export.md:222 +#, fuzzy +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 "" +"O programador deve ler e entender a documentação da API.\n" +"Enquanto alguns consideram esse par para o curso em C, um bom design de API " +"pode atenuar\n" +"este risco. A API POSIX para `DBM` fez isso _consolidando a propriedade_ de\n" +"o iterador com seu pai:" + +#: 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 +#, fuzzy +msgid "" +"Thus, all the lifetimes were bound together, and such unsafety was prevented." +msgstr "Assim, todas as vidas foram unidas e tal insegurança foi evitada." + +#: src\patterns/ffi/export.md:236 +#, fuzzy +msgid "" +"However, this design choice also has a number of drawbacks, which should be\n" +"considered as well." +msgstr "" +"No entanto, esta escolha de design também tem uma série de desvantagens, que " +"devem ser\n" +"considerado também." + +#: src\patterns/ffi/export.md:239 +#, fuzzy +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 "" +"Primeiro, a própria API se torna menos expressiva.\n" +"Com POSIX DBM, há apenas um iterador por objeto e cada chamada muda\n" +"seu estado. Isso é muito mais restritivo do que iteradores em quase qualquer " +"idioma,\n" +"mesmo que seja seguro. Talvez com outros objetos relacionados, cujas vidas " +"são\n" +"menos hierárquica, essa limitação é mais um custo do que a segurança." + +#: src\patterns/ffi/export.md:245 +#, fuzzy +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 "" +"Em segundo lugar, dependendo das relações das partes da API, um esforço de " +"design significativo\n" +"pode estar envolvido. Muitos dos pontos de design mais fáceis têm outros " +"padrões associados\n" +"com eles:" + +#: src\patterns/ffi/export.md:249 +#, fuzzy +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 "" +"- [Consolidação de tipo de wrapper](./wrappers.md) agrupa vários tipos de " +"Rust\n" +" em um \"objeto\" opaco\n" +"\n" +"- [FFI Error Passing](../../idioms/ffi/errors.md) explica o tratamento de " +"erros com número inteiro\n" +" códigos e valores de retorno do sentinela (como ponteiros `NULL`)\n" +"\n" +"- [Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) permite " +"aceitar\n" +" strings com código inseguro mínimo e é mais fácil de acertar do que\n" +" [Passando Strings para FFI](../../idioms/ffi/passing-strings.md)" + +#: src\patterns/ffi/export.md:259 +#, fuzzy +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 "" +"No entanto, nem toda API pode ser feita dessa maneira.\n" +"Cabe ao melhor julgamento do programador saber quem é seu público." + +#: src\patterns/ffi/wrappers.md:1 +#, fuzzy +msgid "# Type Consolidation into Wrappers" +msgstr "# Digite a consolidação em wrappers" + +#: src\patterns/ffi/wrappers.md:5 +#, fuzzy +msgid "" +"This pattern is designed to allow gracefully handling multiple related " +"types,\n" +"while minimizing the surface area for memory unsafety." +msgstr "" +"Esse padrão foi projetado para permitir o manuseio elegante de vários tipos " +"relacionados,\n" +"enquanto minimiza a área de superfície para insegurança de memória." + +#: src\patterns/ffi/wrappers.md:8 +#, fuzzy +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 "" +"Um dos pilares das regras de aliasing de Rust são os tempos de vida.\n" +"Isso garante que muitos padrões de acesso entre os tipos possam ser seguros " +"para a memória,\n" +"segurança de corrida de dados incluída." + +#: src\patterns/ffi/wrappers.md:12 +#, fuzzy +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 "" +"No entanto, quando os tipos Rust são exportados para outros idiomas, eles " +"geralmente são transformados\n" +"em ponteiros. Em Rust, um ponteiro significa \"o usuário gerencia o tempo de " +"vida da ponta\".\n" +"É sua responsabilidade evitar a insegurança da memória." + +#: src\patterns/ffi/wrappers.md:16 +#, fuzzy +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 "" +"Algum nível de confiança no código do usuário é, portanto, necessário, " +"principalmente em torno do use-after-free\n" +"sobre o qual Rust não pode fazer nada. No entanto, alguns designs de API " +"impõem cargas maiores\n" +"do que outros no código escrito no outro idioma." + +#: src\patterns/ffi/wrappers.md:20 +#, fuzzy +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 "" +"A API de menor risco é o \"wrapper consolidado\", onde todas as interações " +"possíveis\n" +"com um objeto são dobrados em um \"tipo wrapper\", mantendo a API Rust limpa." + +#: src\patterns/ffi/wrappers.md:25 +#, fuzzy +msgid "" +"To understand this, let us look at a classic example of an API to export: " +"iteration\n" +"through a collection." +msgstr "" +"Para entender isso, vejamos um exemplo clássico de uma API para exportar: " +"iteração\n" +"através de uma coleção." + +#: src\patterns/ffi/wrappers.md:28 +#, fuzzy +msgid "That API looks like this:" +msgstr "Essa API se parece com isso:" + +#: src\patterns/ffi/wrappers.md:30 +#, fuzzy +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 "" +"1. O iterador é inicializado com `first_key`.\n" +"2. Cada chamada para `next_key` avançará o iterador.\n" +"3. Chamadas para `next_key` se o iterador estiver no final não farão nada.\n" +"4. Conforme observado acima, o iterador é \"envolto\" na coleção (ao " +"contrário do nativo\n" +" API de ferrugem)." + +#: src\patterns/ffi/wrappers.md:36 +#, fuzzy +msgid "" +"If the iterator implements `nth()` efficiently, then it is possible to make " +"it\n" +"ephemeral to each function call:" +msgstr "" +"Se o iterador implementa `nth()` de forma eficiente, então é possível " +"torná-lo\n" +"efêmero para cada chamada de função:" + +#: 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 +#, fuzzy +msgid "As a result, the wrapper is simple and contains no `unsafe` code." +msgstr "" +"Como resultado, o wrapper é simples e não contém nenhum código `inseguro`." + +#: src\patterns/ffi/wrappers.md:65 +#, fuzzy +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 "" +"Isso torna as APIs mais seguras de usar, evitando problemas com tempos de " +"vida entre os tipos.\n" +"Consulte [APIs baseadas em objetos](./export.md) para saber mais sobre as " +"vantagens e armadilhas\n" +"isso evita." + +#: src\patterns/ffi/wrappers.md:71 +#, fuzzy +msgid "" +"Often, wrapping types is quite difficult, and sometimes a Rust API " +"compromise\n" +"would make things easier." +msgstr "" +"Freqüentemente, os tipos de empacotamento são bastante difíceis e, às vezes, " +"um comprometimento da Rust API\n" +"facilitaria as coisas." + +#: src\patterns/ffi/wrappers.md:74 +#, fuzzy +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 "" +"Como exemplo, considere um iterador que não implementa eficientemente " +"`nth()`.\n" +"Definitivamente valeria a pena colocar uma lógica especial para fazer o " +"objeto manipular\n" +"iteração internamente, ou para suportar um padrão de acesso diferente de " +"forma eficiente que\n" +"somente a API de Função Estrangeira usará." + +#: src\patterns/ffi/wrappers.md:79 +#, fuzzy +msgid "### Trying to Wrap Iterators (and Failing)" +msgstr "### Tentando agrupar iteradores (e falhando)" + +#: src\patterns/ffi/wrappers.md:81 +#, fuzzy +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 "" +"Para agrupar qualquer tipo de iterador na API corretamente, o empacotador " +"precisaria\n" +"fazer o que uma versão C do código faria: apagar o tempo de vida do " +"iterador,\n" +"e gerenciá-lo manualmente." + +#: src\patterns/ffi/wrappers.md:85 +#, fuzzy +msgid "Suffice it to say, this is _incredibly_ difficult." +msgstr "Basta dizer que isso é _incrivelmente_ difícil." + +#: src\patterns/ffi/wrappers.md:87 +#, fuzzy +msgid "Here is an illustration of just _one_ pitfall." +msgstr "Aqui está uma ilustração de apenas uma armadilha." + +#: src\patterns/ffi/wrappers.md:89 +#, fuzzy +msgid "A first version of `MySetWrapper` would look like this:" +msgstr "Uma primeira versão de `MySetWrapper` ficaria assim:" + +#: 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 +#, fuzzy +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 "" +"Com `transmutar` sendo usado para estender uma vida, e um ponteiro para " +"ocultá-lo,\n" +"já está feio. Mas fica ainda pior: _qualquer outra operação pode causar\n" +"Rust `comportamento indefinido`_." + +#: src\patterns/ffi/wrappers.md:104 +#, fuzzy +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 "" +"Considere que o `MySet` no wrapper pode ser manipulado por outros\n" +"funções durante a iteração, como armazenar um novo valor na chave que foi\n" +"iterando. A API não desencoraja isso e, de fato, alguns C semelhantes\n" +"as bibliotecas esperam isso." + +#: src\patterns/ffi/wrappers.md:109 +#, fuzzy +msgid "A simple implementation of `myset_store` would be:" +msgstr "Uma implementação simples de `myset_store` seria:" + +#: 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 +#, fuzzy +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 "" +"Se o iterador existir quando esta função for chamada, violamos uma das " +"regras do Rust\n" +"regras de alias. De acordo com Rust, a referência mutável neste bloco deve " +"ter\n" +"acesso _exclusivo_ ao objeto. Se o iterador simplesmente existir, não é " +"exclusivo,\n" +"então temos `comportamento indefinido`!" + +#: src\patterns/ffi/wrappers.md:142 +#, fuzzy +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 "" +"Para evitar isso, devemos ter uma maneira de garantir que a referência " +"mutável seja realmente exclusiva.\n" +"Isso basicamente significa limpar a referência compartilhada do iterador " +"enquanto ela existe,\n" +"e depois reconstruí-lo. Na maioria dos casos, isso ainda será menos " +"eficiente do que\n" +"a versão C." + +#: src\patterns/ffi/wrappers.md:147 +#, fuzzy +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 "" +"Alguns podem perguntar: como C pode fazer isso de forma mais eficiente?\n" +"A resposta é: engana. As regras de aliasing do Rust são o problema, e C " +"simplesmente ignora\n" +"eles por seus ponteiros. Em troca, é comum ver código declarado\n" +"no manual como \"não thread-safe\" em algumas ou todas as circunstâncias. Na " +"verdade,\n" +"a [biblioteca GNU " +"C](https://manpages.debian.org/buster/manpages/attributes.7.en.html)\n" +"tem todo um léxico dedicado ao comportamento simultâneo!" + +#: src\patterns/ffi/wrappers.md:154 +#, fuzzy +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 "" +"Rust prefere tornar tudo seguro para a memória o tempo todo, tanto para " +"segurança quanto para\n" +"otimizações que o código C não pode atingir. Ser negado o acesso a certos " +"atalhos\n" +"é o preço que os programadores Rust precisam pagar." + +#: src\patterns/ffi/wrappers.md:158 +#, fuzzy +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 "" +"Para os programadores C que estão coçando a cabeça, o iterador precisa\n" +"não ser lido _durante_ este código causa o UB. A regra de exclusividade " +"também permite\n" +"otimizações do compilador que podem causar observações inconsistentes por " +"parte do iterador\n" +"referência compartilhada (por exemplo, derramamentos de pilha ou " +"reordenamento de instruções para eficiência).\n" +"Essas observações podem acontecer _a qualquer momento após_ a referência " +"mutável ser criada." + +#: src\anti_patterns/index.md:1 +#, fuzzy +msgid "# Anti-patterns" +msgstr "# Antipadrões" + +#: src\anti_patterns/index.md:3 +#, fuzzy +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 "" +"Um [anti-padrão](https://en.wikipedia.org/wiki/Anti-padrão) é uma solução " +"para\n" +"um \"problema recorrente que geralmente é ineficaz e corre o risco de ser " +"altamente\n" +"contraproducente\". Tão valioso quanto saber resolver um problema, é\n" +"sabendo _não_ resolvê-lo. Os antipadrões nos dão ótimos contra-exemplos " +"para\n" +"considerar em relação aos padrões de projeto. Os antipadrões não estão " +"confinados ao código.\n" +"Por exemplo, um processo também pode ser um antipadrão." + +#: src\anti_patterns/borrow_clone.md:1 +#, fuzzy +msgid "# Clone to satisfy the borrow checker" +msgstr "# Clone para satisfazer o verificador de empréstimo" + +#: src\anti_patterns/borrow_clone.md:5 +#, fuzzy +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 "" +"O verificador de empréstimo impede que os usuários do Rust desenvolvam " +"códigos inseguros,\n" +"garantindo que: apenas uma referência mutável existe, ou potencialmente " +"muitas, mas\n" +"todas as referências imutáveis existem. Se o código escrito não for fiel a " +"essas\n" +"condições, esse antipadrão surge quando o desenvolvedor resolve o problema " +"do compilador\n" +"erro ao clonar a variável." + +#: 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 +#, fuzzy +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 "" +"É tentador, principalmente para iniciantes, usar esse padrão para resolver\n" +"questões confusas com o verificador de empréstimo. No entanto, existem " +"graves\n" +"consequências. O uso de `.clone()` faz com que uma cópia dos dados seja " +"feita. Qualquer alteração\n" +"entre os dois não estão sincronizados - como se duas variáveis completamente " +"separadas\n" +"existir." + +#: src\anti_patterns/borrow_clone.md:38 +#, fuzzy +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 "" +"Existem casos especiais -- `Rc` é projetado para lidar com clones de " +"forma inteligente.\n" +"Ele gerencia internamente exatamente uma cópia dos dados e a clonagem só\n" +"clonar a referência." + +#: src\anti_patterns/borrow_clone.md:42 +#, fuzzy +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 "" +"Há também `Arc` que fornece propriedade compartilhada de um valor do tipo " +"T\n" +"que está alocado no heap. Invocar `.clone()` em `Arc` produz um novo `Arc`\n" +"instância, que aponta para a mesma alocação no heap que a origem `Arc`,\n" +"enquanto aumenta uma contagem de referência." + +#: src\anti_patterns/borrow_clone.md:47 +#, fuzzy +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 "" +"Em geral, os clones devem ser deliberados, com total compreensão do\n" +"consequências. Se um clone for usado para fazer desaparecer um erro do " +"verificador de empréstimo,\n" +"essa é uma boa indicação de que esse antipadrão pode estar em uso." + +#: src\anti_patterns/borrow_clone.md:51 +#, fuzzy +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 "" +"Mesmo que `.clone()` seja uma indicação de um padrão ruim, às vezes\n" +"**é bom escrever código ineficiente**, em casos como quando:" + +#: src\anti_patterns/borrow_clone.md:54 +#, fuzzy +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 "" +"- o desenvolvedor ainda é novo na propriedade\n" +"- o código não tem grandes restrições de velocidade ou memória\n" +" (como projetos ou protótipos de hackathon)\n" +"- satisfazer o verificador de empréstimo é realmente complicado e você " +"prefere\n" +" otimizar a legibilidade sobre o desempenho" + +#: src\anti_patterns/borrow_clone.md:60 +#, fuzzy +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 "" +"Se houver suspeita de um clone desnecessário, o [capítulo do Rust Book sobre " +"propriedade](https://doc.rust-lang.org/book/ownership.html)\n" +"deve ser totalmente compreendido antes de avaliar se o clone é necessário ou " +"não." + +#: src\anti_patterns/borrow_clone.md:63 +#, fuzzy +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 "" +"Certifique-se também de sempre executar `cargo clippy` em seu projeto, o que " +"detectará alguns\n" +"casos em que `.clone()` não é necessário, como " +"[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) ou " +"[4](https://rust-lang.github.io/rust-clippy/master " +"/index.html#clone_double_ref)." + +#: src\anti_patterns/borrow_clone.md:70 +#, fuzzy +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 "" +"- [`mem::{take(_), replace(_)}` para manter os valores de propriedade em " +"enums alterados](../idioms/mem-replace.md)\n" +"- [documentação `Rc`, que lida com .clone() de forma " +"inteligente](http://doc.rust-lang.org/std/rc/)\n" +"- [Documentação do `Arc`, um ponteiro de contagem de referência " +"thread-safe](https://doc.rust-lang.org/std/sync/struct.Arc.html)\n" +"- [Truques com propriedade em " +"Rust](https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html)" + +#: src\anti_patterns/deny-warnings.md:1 +#, fuzzy +msgid "# `#![deny(warnings)]`" +msgstr "# `#![negar(avisos)]`" + +#: src\anti_patterns/deny-warnings.md:5 +#, fuzzy +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 "" +"Um criador de caixas bem-intencionado quer garantir que seu código seja " +"construído sem\n" +"avisos. Então, eles anotam a raiz da caixa com o seguinte:" + +#: 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 +#, fuzzy +msgid "It is short and will stop the build if anything is amiss." +msgstr "É curto e interromperá a construção se algo estiver errado." + +#: src\anti_patterns/deny-warnings.md:20 +#, fuzzy +msgid "## Drawbacks" +msgstr "## Desvantagens" + +#: src\anti_patterns/deny-warnings.md:22 +#, fuzzy +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 "" +"Ao não permitir que o compilador construa com avisos, um autor de caixa opta " +"por não\n" +"A famosa estabilidade de Rust. Às vezes, novos recursos ou antigos erros " +"precisam de uma mudança\n" +"em como as coisas são feitas, assim são escritos lints que 'advertem' para " +"uma certa graça\n" +"período antes de ser transformado em `negar`." + +#: src\anti_patterns/deny-warnings.md:27 +#, fuzzy +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 "" +"Por exemplo, descobriu-se que um tipo poderia ter dois `impl`s com o mesmo\n" +"método. Isso foi considerado uma má ideia, mas para tornar a transição " +"suave,\n" +"o lint `overlapping-inherent-impls` foi introduzido para dar um aviso " +"àqueles\n" +"tropeçando nesse fato, antes que se torne um erro grave em uma versão futura." + +#: src\anti_patterns/deny-warnings.md:32 +#, fuzzy +msgid "" +"Also sometimes APIs get deprecated, so their use will emit a warning where\n" +"before there was none." +msgstr "" +"Às vezes, as APIs ficam obsoletas, portanto, seu uso emitirá um aviso onde\n" +"antes não havia nenhum." + +#: src\anti_patterns/deny-warnings.md:35 +#, fuzzy +msgid "" +"All this conspires to potentially break the build whenever something changes." +msgstr "" +"Tudo isso conspira para potencialmente quebrar a construção sempre que algo " +"mudar." + +#: src\anti_patterns/deny-warnings.md:37 +#, fuzzy +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 "" +"Além disso, as caixas que fornecem fiapos adicionais (por exemplo, " +"[ferrugem-clippy]) não podem\n" +"não será mais usado, a menos que a anotação seja removida. Isso é mitigado " +"com\n" +"[--cap-lints]. O argumento de linha de comando `--cap-lints=warn` transforma " +"todos os `deny`\n" +"erros lint em avisos." + +#: src\anti_patterns/deny-warnings.md:42 +#: src\functional/generics-type-classes.md:227 +#, fuzzy +msgid "## Alternatives" +msgstr "## Alternativas" + +#: src\anti_patterns/deny-warnings.md:44 +#, fuzzy +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 "" +"Existem duas maneiras de lidar com esse problema: primeiro, podemos " +"desacoplar a construção\n" +"configuração do código e, segundo, podemos nomear os lints que queremos " +"negar\n" +"explicitamente." + +#: src\anti_patterns/deny-warnings.md:48 +#, fuzzy +msgid "The following command line will build with all warnings set to `deny`:" +msgstr "" +"A linha de comando a seguir será criada com todos os avisos definidos como " +"`deny`:" + +#: src\anti_patterns/deny-warnings.md:50 +#, fuzzy +msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" +msgstr "`RUSTFLAGS=\"-D warnings\" construção de carga`" + +#: src\anti_patterns/deny-warnings.md:52 +#, fuzzy +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 "" +"Isso pode ser feito por qualquer desenvolvedor individual (ou pode ser " +"configurado em uma ferramenta CI como\n" +"Travis, mas lembre-se que isso pode quebrar a construção quando algo mudar)\n" +"sem exigir alteração no código." + +#: src\anti_patterns/deny-warnings.md:56 +#, fuzzy +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 "" +"Como alternativa, podemos especificar os lints que queremos `negar` no " +"código.\n" +"Aqui está uma lista de lints de aviso que é (espero) seguro negar (a partir " +"de Rustc 1.48.0):" + +#: 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 +#, fuzzy +msgid "In addition, the following `allow`ed lints may be a good idea to `deny`:" +msgstr "" +"Além disso, os seguintes lints permitidos podem ser uma boa ideia para negar:" + +#: 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 +#, fuzzy +msgid "Some may also want to add `missing-copy-implementations` to their list." +msgstr "" +"Alguns também podem querer adicionar `missing-copy-implementations` à sua " +"lista." + +#: src\anti_patterns/deny-warnings.md:93 +#, fuzzy +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 "" +"Observe que não adicionamos explicitamente o lint `obsoleto`, pois é " +"bastante\n" +"certo de que haverá mais APIs obsoletas no futuro." + +#: src\anti_patterns/deny-warnings.md:98 +#, fuzzy +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 "" +"- [Uma coleção de todos os lints " +"clippy](https://rust-lang.github.io/rust-clippy/master)\n" +"- [atributo obsoleto] documentação\n" +"- Digite `rustc -W help` para obter uma lista de lints em seu sistema. " +"Digite também\n" +" `rustc --help` para uma lista geral de opções\n" +"- [rust-clippy] é uma coleção de lints para melhorar o código Rust" + +#: src\anti_patterns/deref.md:1 +#, fuzzy +msgid "# `Deref` polymorphism" +msgstr "# Polimorfismo `Deref`" + +#: src\anti_patterns/deref.md:5 +#, fuzzy +msgid "" +"Misuse the `Deref` trait to emulate inheritance between structs, and thus " +"reuse\n" +"methods." +msgstr "" +"Use mal o trait `Deref` para emular a herança entre structs e, assim, " +"reutilizar\n" +"métodos." + +#: src\anti_patterns/deref.md:10 +#, fuzzy +msgid "" +"Sometimes we want to emulate the following common pattern from OO languages " +"such\n" +"as Java:" +msgstr "" +"Às vezes, queremos emular o seguinte padrão comum de linguagens OO, como\n" +"como Java:" + +#: 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 +#, fuzzy +msgid "We can use the deref polymorphism anti-pattern to do so:" +msgstr "Podemos usar o antipadrão de polimorfismo deref para fazer isso:" + +#: 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 +#, fuzzy +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 "" +"Não há herança de struct no Rust. Em vez disso, usamos composição e " +"incluímos\n" +"uma instância de `Foo` em `Bar` (como o campo é um valor, ele é armazenado " +"em linha,\n" +"portanto, se houvesse campos, eles teriam o mesmo layout na memória que o " +"Java\n" +"versão (provavelmente, você deve usar `#[repr(C)]` se quiser ter certeza))." + +#: src\anti_patterns/deref.md:61 +#, fuzzy +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 "" +"Para fazer a chamada do método funcionar, implementamos `Deref` para `Bar` " +"com `Foo`\n" +"como o destino (retornando o campo `Foo` incorporado). Isso significa que " +"quando nós\n" +"desreferenciar um `Bar` (por exemplo, usando `*`) então obteremos um `Foo`. " +"Aquilo é\n" +"bem estranho. Desreferenciar geralmente dá um `T` de uma referência a `T`, " +"aqui nós\n" +"têm dois tipos não relacionados. No entanto, como o operador ponto " +"implícito\n" +"desreferenciação, isso significa que a chamada do método irá procurar " +"métodos em `Foo` como\n" +"bem como 'Bar'." + +#: src\anti_patterns/deref.md:71 +#, fuzzy +msgid "You save a little boilerplate, e.g.," +msgstr "Você economiza um pouco clichê, por exemplo," + +#: 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 +#, fuzzy +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 "" +"Mais importante, este é um idioma surpreendente - futuros programadores " +"lendo isso em\n" +"código não espera que isso aconteça. Isso porque estamos usando mal o " +"`Deref`\n" +"traço em vez de usá-lo como pretendido (e documentado, etc.). é também " +"porque\n" +"o mecanismo aqui é completamente implícito." + +#: src\anti_patterns/deref.md:88 +#, fuzzy +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 "" +"Este padrão não introduz subtipagem entre `Foo` e `Bar` como\n" +"herança em Java ou C++ faz. Além disso, as características implementadas por " +"`Foo` são\n" +"não implementado automaticamente para `Bar`, então este padrão interage mal " +"com\n" +"verificação de limites e, portanto, programação genérica." + +#: src\anti_patterns/deref.md:93 +#, fuzzy +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 "" +"O uso desse padrão fornece uma semântica sutilmente diferente da maioria das " +"linguagens OO com\n" +"diz respeito a 'eu'. Normalmente permanece uma referência à subclasse, com " +"este\n" +"pattern será a 'classe' onde o método é definido." + +#: src\anti_patterns/deref.md:97 +#, fuzzy +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 "" +"Por fim, esse padrão suporta apenas herança única e não tem noção de\n" +"interfaces, privacidade baseada em classe ou outros recursos relacionados à " +"herança. Então, é\n" +"oferece uma experiência que surpreenderá sutilmente os programadores " +"acostumados com Java\n" +"herança, etc" + +#: src\anti_patterns/deref.md:104 +#, fuzzy +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 "" +"Não há uma boa alternativa. Dependendo das circunstâncias exatas, pode\n" +"seria melhor reimplementar usando traits ou escrever os métodos de fachada " +"para\n" +"despachar para `Foo` manualmente. Pretendemos adicionar um mecanismo para " +"herança\n" +"semelhante a isso para Rust, mas é provável que demore algum tempo antes de " +"atingir\n" +"ferrugem estável. Veja estes " +"[blog](http://aturon.github.io/blog/2015/09/18/reuse/)\n" +"[postagens](http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/)\n" +"e este [problema RFC](https://github.com/rust-lang/rfcs/issues/349) para " +"mais detalhes." + +#: src\anti_patterns/deref.md:112 +#, fuzzy +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 "" +"O trait `Deref` é projetado para a implementação de tipos de ponteiro " +"personalizados.\n" +"A intenção é que ele leve um ponteiro para `T` para um `T`, não converta\n" +"entre diferentes tipos. É uma pena que isso não seja (provavelmente não pode " +"ser)\n" +"imposta pela definição do traço." + +#: src\anti_patterns/deref.md:117 +#, fuzzy +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 "" +"Rust tenta encontrar um equilíbrio cuidadoso entre mecanismos explícitos e " +"implícitos,\n" +"favorecendo conversões explícitas entre tipos. Desreferenciamento automático " +"no ponto\n" +"operador é um caso onde a ergonomia favorece fortemente um mecanismo " +"implícito,\n" +"mas a intenção é que isso seja limitado a graus de indireção, não\n" +"conversão entre tipos arbitrários." + +#: src\anti_patterns/deref.md:125 +#, fuzzy +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 "" +"- [Coleções são idiomas de ponteiros inteligentes](../idioms/deref.md).\n" +"- Caixas de delegação por menos padrão como " +"[delegate](https://crates.io/crates/delegate)\n" +" ou [embaixador](https://crates.io/crates/ambassador)\n" +"- [Documentação para o trait " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\functional/index.md:1 +#, fuzzy +msgid "# Functional Usage of Rust" +msgstr "# Uso Funcional de Rust" + +#: src\functional/index.md:3 +#, fuzzy +msgid "" +"Rust is an imperative language, but it follows many\n" +"[functional " +"programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms." +msgstr "" +"A ferrugem é uma linguagem imperativa, mas segue muitas\n" +"[programação " +"funcional](https://en.wikipedia.org/wiki/Functional_programming) paradigmas." + +#: src\functional/index.md:6 +#, fuzzy +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 "" +"> Em ciência da computação, _programação funcional_ é um paradigma de " +"programação onde\n" +"> os programas são construídos aplicando e compondo funções.\n" +"> É um paradigma de programação declarativa em que as definições de funções " +"são\n" +"> árvores de expressões que retornam um valor, em vez de uma sequência de\n" +"> declarações imperativas que mudam o estado do programa." + +#: src\functional/paradigms.md:1 +#, fuzzy +msgid "# Programming paradigms" +msgstr "# Paradigmas de programação" + +#: src\functional/paradigms.md:3 +#, fuzzy +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 "" +"Um dos maiores obstáculos para a compreensão dos programas funcionais ao " +"chegar\n" +"de um fundo imperativo é a mudança no pensamento. programas imperativos\n" +"descrevem **como** fazer algo, enquanto os programas declarativos descrevem\n" +"**o que fazer. Vamos somar os números de 1 a 10 para mostrar isso." + +#: src\functional/paradigms.md:8 +#, fuzzy +msgid "## Imperative" +msgstr "## Imperativo" + +#: 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 +#, fuzzy +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 "" +"Com programas imperativos, temos que jogar compilador para ver o que está " +"acontecendo.\n" +"Aqui, começamos com uma `soma` de `0`.\n" +"Em seguida, iteramos pelo intervalo de 1 a 10.\n" +"Cada vez que passamos pelo loop, adicionamos o valor correspondente no " +"intervalo.\n" +"Depois imprimimos." + +#: src\functional/paradigms.md:24 +#, fuzzy +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 "" +"| `eu` | `soma` |\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 |" + +#: src\functional/paradigms.md:37 +#, fuzzy +msgid "" +"This is how most of us start out programming. We learn that a program is a " +"set\n" +"of steps." +msgstr "" +"É assim que a maioria de nós começa a programar. Aprendemos que um programa " +"é um conjunto\n" +"de passos." + +#: src\functional/paradigms.md:40 +#, fuzzy +msgid "## Declarative" +msgstr "## Declarativo" + +#: src\functional/paradigms.md:42 +msgid "" +"```rust\n" +"println!(\"{}\", (1..11).fold(0, |a, b| a + b));\n" +"```" +msgstr "" + +#: src\functional/paradigms.md:46 +#, fuzzy +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 "" +"Uau! Isso é realmente diferente! O que está acontecendo aqui?\n" +"Lembre-se que com programas declarativos estamos descrevendo **o que** " +"fazer,\n" +"em vez de **como** fazer. `fold` é uma função que " +"[compõe](https://en.wikipedia.org/wiki/Function_composition)\n" +"funções. O nome é uma convenção de Haskell." + +#: src\functional/paradigms.md:51 +#, fuzzy +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 "" +"Aqui, estamos compondo funções de adição (este fechamento: `|a, b| a + b`)\n" +"com um intervalo de 1 a 10. O `0` é o ponto de partida, então `a` é `0` em\n" +"primeiro. `b` é o primeiro elemento do intervalo, `1`. `0 + 1 = 1` é o " +"resultado.\n" +"Então agora nós `fold` novamente, com `a = 1`, `b = 2` e então `1 + 2 = 3` é " +"o próximo\n" +"resultado. Esse processo continua até chegarmos ao último elemento do " +"intervalo,\n" +"`10`." + +#: src\functional/paradigms.md:58 +#, fuzzy +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 "" +"| `a` | `b` | resultado |\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/generics-type-classes.md:1 +#, fuzzy +msgid "# Generics as Type Classes" +msgstr "# Generics as Type Classes" + +#: src\functional/generics-type-classes.md:5 +#, fuzzy +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 "" +"O sistema de tipos do Rust é projetado mais como linguagens funcionais (como " +"Haskell)\n" +"em vez de linguagens imperativas (como Java e C++). Como resultado, Rust " +"pode transformar\n" +"muitos tipos de problemas de programação em problemas de \"digitação " +"estática\". Isso é um\n" +"das maiores vitórias de escolher uma linguagem funcional, e é fundamental " +"para muitos\n" +"das garantias de tempo de compilação do Rust." + +#: src\functional/generics-type-classes.md:11 +#, fuzzy +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 "" +"Uma parte fundamental dessa ideia é a maneira como os tipos genéricos " +"funcionam. Em C++ e Java, por\n" +"Por exemplo, os tipos genéricos são uma construção de metaprogramação para o " +"compilador.\n" +"`vector` e `vector` em C++ são apenas duas cópias diferentes do\n" +"mesmo código clichê para um tipo `vector` (conhecido como `template`) com " +"dois\n" +"diferentes tipos preenchidos." + +#: src\functional/generics-type-classes.md:17 +#, fuzzy +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 "" +"No Rust, um parâmetro de tipo genérico cria o que é conhecido em linguagens " +"funcionais\n" +"como uma \"restrição de classe de tipo\", e cada parâmetro diferente " +"preenchido por um final\n" +"o usuário _realmente muda o tipo_. Em outras palavras, `Vec` e " +"`Vec`\n" +"_são dois tipos diferentes_, que são reconhecidos como distintos por todas " +"as partes do\n" +"tipo de sistema." + +#: src\functional/generics-type-classes.md:23 +#, fuzzy +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 "" +"Isso é chamado de **monomorfização**, onde diferentes tipos são criados a " +"partir de\n" +"Código **polimórfico**. Este comportamento especial requer blocos `impl` " +"para especificar\n" +"parâmetros genéricos. Valores diferentes para o tipo genérico causam tipos " +"diferentes,\n" +"e diferentes tipos podem ter diferentes blocos `impl`." + +#: src\functional/generics-type-classes.md:28 +#, fuzzy +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 "" +"Em linguagens orientadas a objetos, as classes podem herdar o comportamento " +"de seus pais.\n" +"No entanto, isso permite a anexação não apenas de comportamento adicional a\n" +"membros particulares de uma classe de tipo, mas comportamento extra também." + +#: src\functional/generics-type-classes.md:32 +#, fuzzy +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 "" +"O equivalente mais próximo é o polimorfismo de tempo de execução em " +"Javascript e Python,\n" +"onde novos membros podem ser adicionados a objetos por qualquer construtor.\n" +"No entanto, ao contrário dessas linguagens, todos os métodos adicionais do " +"Rust podem ser digitados\n" +"verificados quando são usados, porque seus genéricos são definidos " +"estaticamente. Que\n" +"torna-os mais utilizáveis enquanto permanecem seguros." + +#: src\functional/generics-type-classes.md:40 +#, fuzzy +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 "" +"Suponha que você esteja projetando um servidor de armazenamento para uma " +"série de máquinas de laboratório.\n" +"Devido ao software envolvido, existem dois protocolos diferentes que você " +"precisa\n" +"para suportar: BOOTP (para inicialização de rede PXE) e NFS (para " +"armazenamento de montagem remota)." + +#: src\functional/generics-type-classes.md:44 +#, fuzzy +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 "" +"Seu objetivo é ter um programa, escrito em Rust, que possa lidar com ambos\n" +"eles. Ele terá manipuladores de protocolo e escutará ambos os tipos de " +"solicitações. O\n" +"a lógica do aplicativo principal permitirá que um administrador de " +"laboratório configure o armazenamento\n" +"e controles de segurança para os arquivos reais." + +#: src\functional/generics-type-classes.md:49 +#, fuzzy +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 "" +"As solicitações de máquinas no laboratório para arquivos contêm o mesmo " +"básico\n" +"informações, independentemente do protocolo de onde vieram: um método de " +"autenticação,\n" +"e um nome de arquivo para recuperar. Uma implementação direta pareceria\n" +"algo assim:" + +#: 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 +#, fuzzy +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 "" +"Este design pode funcionar bem o suficiente. Mas agora suponha que você " +"precise apoiar\n" +"adicionando metadados que eram _protocolos específicos_. Por exemplo, com o " +"NFS, você\n" +"queria determinar qual era o seu ponto de montagem para impor\n" +"regras de segurança." + +#: src\functional/generics-type-classes.md:71 +#, fuzzy +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 "" +"A maneira como a estrutura atual é projetada deixa a decisão do protocolo " +"até\n" +"tempo de execução. Isso significa qualquer método que se aplique a um " +"protocolo e não ao outro\n" +"requer que o programador faça uma verificação de tempo de execução." + +#: src\functional/generics-type-classes.md:75 +#, fuzzy +msgid "Here is how getting an NFS mount point would look:" +msgstr "Aqui está como obter um ponto de montagem NFS seria:" + +#: 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 +#, fuzzy +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 "" +"Todo chamador de `mount_point()` deve verificar `None` e escrever o código " +"para manipular\n" +"isto. Isso é verdade mesmo que eles saibam que apenas solicitações NFS são " +"usadas em um determinado\n" +"caminho do código!" + +#: src\functional/generics-type-classes.md:99 +#, fuzzy +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 "" +"Seria muito mais ideal causar um erro de tempo de compilação se os " +"diferentes\n" +"os tipos de solicitação eram confusos. Afinal, todo o caminho do código do " +"usuário,\n" +"incluindo quais funções da biblioteca eles usam, saberão se uma solicitação\n" +"é uma solicitação NFS ou uma solicitação BOOTP." + +#: src\functional/generics-type-classes.md:104 +#, fuzzy +msgid "" +"In Rust, this is actually possible! The solution is to _add a generic type_ " +"in\n" +"order to split the API." +msgstr "" +"No Rust, isso é realmente possível! A solução é _adicionar um tipo genérico_ " +"em\n" +"para dividir a API." + +#: src\functional/generics-type-classes.md:107 +#, fuzzy +msgid "Here is what that looks like:" +msgstr "Aqui está o que parece:" + +#: 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 +#, fuzzy +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 "" +"Eles receberiam um erro de sintaxe. O tipo `FileDownloadRequest` não\n" +"implementar `mount_point()`, apenas o tipo `FileDownloadRequest` o faz. " +"E\n" +"que é criado pelo módulo NFS, não pelo módulo BOOTP, é claro!" + +#: src\functional/generics-type-classes.md:212 +#, fuzzy +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 "" +"Primeiro, permite que os campos comuns a vários estados sejam " +"desduplicados.\n" +"Ao tornar os campos não compartilhados genéricos, eles são implementados uma " +"vez." + +#: src\functional/generics-type-classes.md:215 +#, fuzzy +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 "" +"Em segundo lugar, torna os blocos `impl` mais fáceis de ler, porque eles são " +"divididos\n" +"por estado. Os métodos comuns a todos os estados são digitados uma vez em um " +"bloco e os métodos\n" +"exclusivos para um estado estão em um bloco separado." + +#: src\functional/generics-type-classes.md:219 +#, fuzzy +msgid "" +"Both of these mean there are fewer lines of code, and they are better " +"organized." +msgstr "" +"Ambos significam que há menos linhas de código e são mais bem organizados." + +#: src\functional/generics-type-classes.md:223 +#, fuzzy +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 "" +"Isso atualmente aumenta o tamanho do binário, devido à forma como a " +"monomorfização\n" +"é implementado no compilador. Esperamos que a implementação seja capaz de\n" +"melhorar no futuro." + +#: src\functional/generics-type-classes.md:229 +#, fuzzy +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 "" +"- Se um tipo parecer precisar de uma \"API dividida\" devido à construção " +"ou\n" +" inicialização, considere o\n" +" [Padrão do construtor](../patterns/creational/builder.md) em vez disso.\n" +"\n" +"- Se a API entre os tipos não mudar -- apenas o comportamento muda -- então\n" +" o [Padrão de Estratégia](../patterns/behavioural/strategy.md) é melhor " +"usado\n" +" em vez de." + +#: src\functional/generics-type-classes.md:239 +#, fuzzy +msgid "This pattern is used throughout the standard library:" +msgstr "Este padrão é usado em toda a biblioteca padrão:" + +#: src\functional/generics-type-classes.md:241 +#, fuzzy +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 "" +"- `Vec` pode ser lançado a partir de uma String, ao contrário de " +"qualquer outro tipo de `Vec`.[^1]\n" +"- Eles também podem ser lançados em um heap binário, mas apenas se " +"contiverem um tipo\n" +" que implementa o traço `Ord`.[^2]\n" +"- O método `to_string` foi especializado para `Cow` apenas do tipo `str`.[^3]" + +#: src\functional/generics-type-classes.md:246 +#, fuzzy +msgid "It is also used by several popular crates to allow API flexibility:" +msgstr "" +"Ele também é usado por várias caixas populares para permitir a flexibilidade " +"da API:" + +#: src\functional/generics-type-classes.md:248 +#, fuzzy +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 "" +"- O ecossistema `embedded-hal` usado para dispositivos embarcados faz uso " +"extensivo de\n" +" esse padrão. Por exemplo, permite verificar estaticamente a configuração " +"de\n" +" registradores de dispositivos usados para controlar pinos embutidos. " +"Quando um pino é colocado em um modo,\n" +" ele retorna uma estrutura `Pin`, cujo genérico determina as funções\n" +" utilizáveis nesse modo, que não estão no próprio `Pin`. [^4]\n" +"\n" +"- A biblioteca de cliente `hiper` HTTP usa isso para expor APIs ricas para " +"diferentes\n" +" solicitações conectáveis. Clientes com conectores diferentes têm métodos " +"diferentes\n" +" sobre eles, bem como implementações de características diferentes, " +"enquanto um conjunto básico de\n" +" Os métodos se aplicam a qualquer conector. [^5]\n" +"\n" +"- O padrão \"tipo de estado\" -- onde um objeto ganha e perde API com base " +"em um\n" +" estado interno ou invariante -- é implementado em Rust usando o mesmo\n" +" conceito e uma técnica ligeiramente diferente. [^6]" + +#: src\functional/generics-type-classes.md:263 +#, fuzzy +msgid "" +"See: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811)" +msgstr "" +"Veja: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811 " +")" + +#: src\functional/generics-type-classes.md:265 +#, fuzzy +msgid "" +"See: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354)" +msgstr "" +"Veja: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections " +"/binary_heap.rs.html#1345-1354)" + +#: src\functional/generics-type-classes.md:267 +#, fuzzy +msgid "" +"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240)" +msgstr "" +"Veja: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235- 2240)" + +#: src\functional/generics-type-classes.md:269 +#, fuzzy +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 "" +"Exemplo:\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/generics-type-classes.md:272 +#, fuzzy +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 "" +"Ver:\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/generics-type-classes.md:275 +#, fuzzy +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 "" +"Ver:\n" +"[O caso para o padrão de estado de " +"tipo](https://web.archive.org/web/20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-typestate- " +"padrão-o-tipo-estado-padrão-em-si/)\n" +"e\n" +"[Série Rusty Typestate (uma tese " +"extensa)](https://web.archive.org/web/20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index " +")" + +#: src\functional/lenses.md:1 +#, fuzzy +msgid "# Lenses and Prisms" +msgstr "# Lentes e Prismas" + +#: src\functional/lenses.md:3 +#, fuzzy +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 "" +"Este é um conceito funcional puro que não é usado com frequência no Rust.\n" +"No entanto, explorar o conceito pode ser útil para entender outras\n" +"padrões em Rust APIs, como [visitors](../patterns/behavioural/visitor.md).\n" +"Eles também têm casos de uso de nicho." + +#: src\functional/lenses.md:8 +#, fuzzy +msgid "## Lenses: Uniform Access Across Types" +msgstr "## Lentes: Acesso uniforme entre os tipos" + +#: src\functional/lenses.md:10 +#, fuzzy +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 "" +"Uma lente é um conceito de linguagens de programação funcional que permite\n" +"acessando partes de um tipo de dados de forma abstrata e unificada.[^1]\n" +"No conceito básico, é semelhante à maneira como as características do Rust " +"funcionam com o apagamento de tipo,\n" +"mas tem um pouco mais de potência e flexibilidade." + +#: src\functional/lenses.md:15 +#, fuzzy +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 "" +"Por exemplo, suponha que um banco contenha vários formatos JSON para " +"clientes\n" +"dados.\n" +"Isso ocorre porque eles vêm de diferentes bancos de dados ou sistemas " +"legados.\n" +"Um banco de dados contém os dados necessários para realizar verificações de " +"crédito:" + +#: 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 +#, fuzzy +msgid "Another one contains the account information:" +msgstr "Outro contém as informações da conta:" + +#: 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 +#, fuzzy +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 "" +"Observe que ambos os tipos têm um número de identificação do cliente que " +"corresponde a uma pessoa.\n" +"Como uma única função lidaria com ambos os registros de tipos diferentes?" + +#: src\functional/lenses.md:50 +#, fuzzy +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 "" +"Em Rust, uma `struct` poderia representar cada um desses tipos, e um trait " +"teria\n" +"uma função `get_customer_id` que eles implementariam:" + +#: 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 +#, fuzzy +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 "" +"As lentes, no entanto, permitem que o código que suporta a ID do cliente " +"seja movido do\n" +"_type_ para a função _accessor_.\n" +"Em vez de implementar uma característica em cada tipo, todas as estruturas " +"correspondentes podem\n" +"simplesmente ser acessado da mesma maneira." + +#: src\functional/lenses.md:109 +#, fuzzy +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 "" +"Embora a própria linguagem Rust não suporte isso (o apagamento de tipo é o\n" +"solução preferida para este problema), o [lens-rs " +"crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) permite o " +"código\n" +"que se sente assim para ser escrito com macros:" + +#: 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 +#, fuzzy +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 "" +"A versão de `unique_ids_lens` mostrada aqui permite que qualquer tipo esteja " +"no iterador,\n" +"desde que tenha um atributo chamado `customer_id` que pode ser acessado por\n" +"a função.\n" +"É assim que a maioria das linguagens de programação funcionais operam nas " +"lentes." + +#: src\functional/lenses.md:154 +#, fuzzy +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 "" +"Em vez de macros, eles conseguem isso com uma técnica conhecida como " +"\"currying\".\n" +"Ou seja, eles \"constroem parcialmente\" a função, deixando o tipo do\n" +"parâmetro final (o valor que está sendo operado) não preenchido até que a " +"função seja\n" +"chamado.\n" +"Assim, pode ser chamado com diferentes tipos dinamicamente, mesmo de um " +"lugar em\n" +"o código.\n" +"Isso é o que `optics!` e `view_ref` no exemplo acima simulam." + +#: src\functional/lenses.md:162 +#, fuzzy +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 "" +"A abordagem funcional não precisa ser restrita aos membros de acesso.\n" +"Podem ser criadas lentes mais poderosas que _configuram_ e _obtêm_ dados em " +"um\n" +"estrutura.\n" +"Mas o conceito realmente se torna interessante quando usado como bloco de " +"construção para\n" +"composição.\n" +"É aí que o conceito aparece com mais clareza em Rust." + +#: src\functional/lenses.md:169 +#, fuzzy +msgid "## Prisms: A Higher-Order form of \"Optics\"" +msgstr "## Prismas: Uma forma de ordem superior de \"Óptica\"" + +#: src\functional/lenses.md:171 +#, fuzzy +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 "" +"Uma função simples como `unique_ids_lens` acima opera em uma única lente.\n" +"Um _prisma_ é uma função que opera em uma _família_ de lentes.\n" +"É um nível conceitual superior, usando lentes como bloco de construção e\n" +"continuando a metáfora, faz parte de uma família de \"ópticas\".\n" +"É o principal que é útil para entender as APIs do Rust, assim será o\n" +"foco aqui." + +#: src\functional/lenses.md:178 +#, fuzzy +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 "" +"Da mesma forma que as características permitem um design \"semelhante a uma " +"lente\" com polimorfismo estático e\n" +"despacho dinâmico, designs semelhantes a prismas aparecem em APIs Rust que " +"dividem problemas\n" +"em vários tipos associados a serem compostos.\n" +"Um bom exemplo disso são as características na caixa de análise _Serde_." + +#: src\functional/lenses.md:183 +#, fuzzy +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 "" +"Tentar entender como o _Serde_ funciona apenas lendo a API é uma\n" +"desafio, especialmente na primeira vez.\n" +"Considere o trait `Deserializer`, implementado por algum tipo em qualquer " +"biblioteca\n" +"que analisa um novo formato:" + +#: 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 +#, fuzzy +msgid "" +"For a trait that is just supposed to parse data from a format and return a\n" +"value, this looks odd." +msgstr "" +"Para uma característica que deve apenas analisar dados de um formato e " +"retornar um\n" +"valor, isso parece estranho." + +#: src\functional/lenses.md:207 +#, fuzzy +msgid "Why are all the return types type erased?" +msgstr "Por que todos os tipos de retorno são apagados?" + +#: src\functional/lenses.md:209 +#, fuzzy +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 "" +"Para entender isso, precisamos manter o conceito de lente em mente e olhar " +"para\n" +"a definição do tipo `Visitor` que é passado genericamente:" + +#: 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 +#, fuzzy +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 "" +"O trabalho do tipo `Visitor` é construir valores no modelo de dados " +"_Serde_,\n" +"que são representados por seu tipo `Value` associado." + +#: src\functional/lenses.md:235 +#, fuzzy +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 "" +"Esses valores representam partes do valor Rust sendo desserializado.\n" +"Se falhar, ele retornará um tipo `Error` - um tipo de erro determinado pelo\n" +"`Deserializer` quando seus métodos foram chamados." + +#: src\functional/lenses.md:239 +#, fuzzy +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 "" +"Isso destaca que `Deserializer` é semelhante a `CustomerId` de antes,\n" +"permitindo que qualquer analisador de formato que o implemente crie " +"`Valores`s com base no que\n" +"ele analisou.\n" +"O traço `Valor` está agindo como uma lente em linguagens de programação " +"funcional." + +#: src\functional/lenses.md:244 +#, fuzzy +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 "" +"Mas ao contrário do trait `CustomerId`, os tipos de retorno dos métodos " +"`Visitor` são\n" +"_genérico_, e o tipo `Valor` concreto é _determinado pelo próprio Visitante_." + +#: src\functional/lenses.md:247 +#, fuzzy +msgid "" +"Instead of acting as one lens, it effectively acts as a family of\n" +"lenses, one for each concrete type of `Visitor`." +msgstr "" +"Em vez de atuar como uma lente, ela efetivamente atua como uma família de\n" +"lentes, uma para cada tipo concreto de 'Visitante'." + +#: src\functional/lenses.md:250 +#, fuzzy +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 "" +"A API `Deserializer` é baseada em ter um conjunto genérico de \"lentes\" " +"trabalhando\n" +"um conjunto de outros tipos genéricos para \"observação\".\n" +"É um _prisma_." + +#: src\functional/lenses.md:254 +#, fuzzy +msgid "For example, consider the identity record from earlier but simplified:" +msgstr "" +"Por exemplo, considere o registro de identidade anterior, mas simplificado:" + +#: src\functional/lenses.md:256 +msgid "" +"```json\n" +"{ \"name\": \"Jane Doe\",\n" +" \"customer_id\": 1048576332,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:262 +#, fuzzy +msgid "" +"How would the _Serde_ library deserialize this JSON into `struct " +"CreditRecord`?" +msgstr "" +"Como a biblioteca _Serde_ desserializaria este JSON em `struct CreditRecord`?" + +#: src\functional/lenses.md:264 +#, fuzzy +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 "" +"1. O usuário chamaria uma função de biblioteca para desserializar os dados. " +"Isso seria\n" +" crie um `Deserializer` baseado no formato JSON.\n" +"1. Com base nos campos da estrutura, um `Visitor` seria criado (mais sobre\n" +" isso daqui a pouco) que sabe como criar cada tipo em um data genérico\n" +" modelo necessário para representá-lo: `u64` e `String`.\n" +"1. O desserializador faria chamadas para o `Visitor` enquanto analisava os " +"itens.\n" +"1. O 'Visitante' indicaria se os itens encontrados eram esperados e, se " +"não,\n" +" gera um erro para indicar que a desserialização falhou." + +#: src\functional/lenses.md:273 +#, fuzzy +msgid "For our very simple structure above, the expected pattern would be:" +msgstr "Para nossa estrutura muito simples acima, o padrão esperado seria:" + +#: src\functional/lenses.md:275 +#, fuzzy +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 "" +"1. Visite um mapa (equivalente de _Serde_ a `HashMap` ou dicionário de " +"JSON).\n" +"1. Visite uma chave de string chamada \"nome\".\n" +"1. Visite um valor de string, que irá para o campo `name`.\n" +"1. Visite uma chave de string chamada \"customer_id\".\n" +"1. Visite um valor de string, que irá para o campo `customer_id`.\n" +"1. Visite o final do mapa." + +#: src\functional/lenses.md:282 +#, fuzzy +msgid "But what determines which \"observation\" pattern is expected?" +msgstr "Mas o que determina qual padrão de \"observação\" é esperado?" + +#: src\functional/lenses.md:284 +#, fuzzy +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 "" +"Uma linguagem de programação funcional seria capaz de usar currying para " +"criar\n" +"reflexão de cada tipo com base no próprio tipo.\n" +"Rust não suporta isso, então cada tipo precisaria ter seu próprio\n" +"código escrito com base em seus campos e suas propriedades." + +#: src\functional/lenses.md:289 +#, fuzzy +msgid "_Serde_ solves this usability challenge with a derive macro:" +msgstr "_Serde_ resolve esse desafio de usabilidade com uma macro de derivação:" + +#: 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 +#, fuzzy +msgid "" +"That macro simply generates an impl block causing the struct to implement a\n" +"trait called `Deserialize`." +msgstr "" +"Essa macro simplesmente gera um bloco impl fazendo com que o struct " +"implemente um\n" +"traço chamado `Deserialize`." + +#: src\functional/lenses.md:304 +#, fuzzy +msgid "It is defined this way:" +msgstr "É definido desta forma:" + +#: 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 +#, fuzzy +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 "" +"Esta é a função que determina como criar a própria estrutura.\n" +"O código é gerado com base nos campos da estrutura.\n" +"Quando a biblioteca de análise é chamada - em nosso exemplo, uma biblioteca " +"de análise JSON -\n" +"ele cria um `Deserializer` e chama `Type::deserialize` com ele como um\n" +"parâmetro." + +#: src\functional/lenses.md:320 +#, fuzzy +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 "" +"O código `deserialize` criará então um `Visitor` que terá suas chamadas\n" +"\"refratado\" pelo `Deserializer`.\n" +"Se tudo correr bem, eventualmente esse `Visitor` construirá um valor\n" +"correspondente ao tipo que está sendo analisado e retorná-lo." + +#: src\functional/lenses.md:325 +#, fuzzy +msgid "" +"For a complete example, see the [_Serde_ " +"documentation](https://serde.rs/deserialize-struct.html)." +msgstr "" +"Para obter um exemplo completo, consulte a [documentação do " +"_Serde_](https://serde.rs/deserialize-struct.html)." + +#: src\functional/lenses.md:327 +#, fuzzy +msgid "To wrap up, this is the power of _Serde_:" +msgstr "Para finalizar, este é o poder do _Serde_:" + +#: src\functional/lenses.md:329 +#, fuzzy +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 "" +"1. A estrutura que está sendo analisada é representada por um bloco `impl` " +"para `Deserialize`\n" +"1. O formato de dados de entrada (por exemplo, JSON) é representado por um " +"`Deserializer` chamado\n" +" por `Deserialize`\n" +"1. O `Deserializer` age como um prisma que \"refrata\" o `Visitor` " +"semelhante a uma lente\n" +" chamadas que realmente constroem o valor dos dados" + +#: src\functional/lenses.md:335 +#, fuzzy +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 "" +"O resultado é que os tipos a serem desserializados implementam apenas a " +"\"camada superior\" de\n" +"a API e os formatos de arquivo só precisam implementar a \"camada " +"inferior\".\n" +"Cada peça pode então \"simplesmente funcionar\" com o resto do ecossistema, " +"desde\n" +"os tipos os unirão." + +#: src\functional/lenses.md:340 +#, fuzzy +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 "" +"Para enfatizar, a única razão pela qual este modelo funciona em qualquer " +"formato e qualquer tipo é\n" +"porque o tipo de saída do trait `Deserializer` ** é especificado pelo\n" +"implementador de `Visitor` é passado**, em vez de ser vinculado a um " +"específico\n" +"tipo.\n" +"Isso não era verdade no exemplo de conta anterior." + +#: src\functional/lenses.md:346 +#, fuzzy +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 "" +"O sistema de tipo de inspiração genérica de Rust pode aproximá-lo desses " +"conceitos e\n" +"use seu poder, conforme mostrado neste design de API.\n" +"Mas também pode precisar de macros processuais para criar pontes para seus " +"genéricos." + +#: src\functional/lenses.md:350 +#, fuzzy +msgid "## See Also" +msgstr "## Veja também" + +#: src\functional/lenses.md:352 +#, fuzzy +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 "" +"- [lens-rs crate](https://crates.io/crates/lens-rs) para lentes " +"pré-construídas\n" +" implementação, com uma interface mais limpa do que esses exemplos\n" +"- [serde](https://serde.rs) em si, o que torna esses conceitos intuitivos " +"para\n" +" usuários finais (isto é, definindo as estruturas) sem precisar entender o\n" +" detalhes\n" +"- [luminância](https://github.com/phaazon/luminance-rs) é uma caixa para " +"desenho\n" +" computação gráfica que usa design de API de lentes, incluindo macros " +"processuais para\n" +" criar prismas completos para buffers de diferentes tipos de pixel que " +"permanecem genéricos\n" +"- [Um artigo sobre lentes em " +"Scala](https://web.archive.org/web/20221128185849/https://medium.com/zyseme-technology/functional-references-lens-and-other-optics-in- " +"scala-e5f7e2fdafe)\n" +" que é muito legível mesmo sem experiência em Scala.\n" +"- [Papel: Profunctor Optics: Modular Data\n" +" " +"Acessadores](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf)" + +#: src\functional/lenses.md:365 +#, fuzzy +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 "" +"[Escola de Haskell: um pequeno tutorial para iniciantes em " +"lentes](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:1 +#, fuzzy +msgid "# Additional resources" +msgstr "# Recursos adicionais" + +#: src\additional_resources/index.md:3 +#, fuzzy +msgid "A collection of complementary helpful content" +msgstr "Uma coleção de conteúdo útil complementar" + +#: src\additional_resources/index.md:5 +#, fuzzy +msgid "## Talks" +msgstr "## Palestras" + +#: src\additional_resources/index.md:7 +#, fuzzy +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 "" +"- [Padrões de design em " +"ferrugem](https://www.youtube.com/watch?v=Pm_oO0N5B9k) por\n" +" Nicholas Cameron no PDRust (2016)\n" +"- [Escrevendo bibliotecas idiomáticas em " +"ferrugem](https://www.youtube.com/watch?v=0zOg8_B71gE)\n" +" por Pascal Hertleif no RustFest (2017)\n" +"- [Técnicas de Programação " +"Rust](https://www.youtube.com/watch?v=vqavdUGKeb4) por\n" +" Nicholas Cameron na LinuxConfAu (2018)" + +#: src\additional_resources/index.md:14 +#, fuzzy +msgid "## Books (Online)" +msgstr "## Livros (On-line)" + +#: src\additional_resources/index.md:16 +#, fuzzy +msgid "- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" +msgstr "- [Diretrizes da Rust API](https://rust-lang.github.io/api-guidelines)" + +#: src\additional_resources/design-principles.md:1 +#, fuzzy +msgid "# Design principles" +msgstr "# Princípios de design" + +#: src\additional_resources/design-principles.md:3 +#, fuzzy +msgid "## A brief overview over common design principles" +msgstr "## Uma breve visão geral sobre os princípios de design comuns" + +#: src\additional_resources/design-principles.md:7 +#, fuzzy +msgid "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" +msgstr "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" + +#: src\additional_resources/design-principles.md:9 +#, fuzzy +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 "" +"- [Princípio de Responsabilidade Única " +"(SRP)](https://en.wikipedia.org/wiki/Single-responsibility_principle):\n" +" Uma classe deve ter apenas uma única responsabilidade, ou seja, apenas " +"alterações\n" +" uma parte da especificação do software deve ser capaz de afetar o\n" +" especificação da classe.\n" +"- [Princípio Aberto/Fechado " +"(OCP)](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle):\n" +" \"Entidades de software ... devem estar abertas para extensão, mas " +"fechadas para\n" +" modificação.\"\n" +"- [Princípio de Substituição de Liskov " +"(LSP)](https://en.wikipedia.org/wiki/Liskov_substitution_principle):\n" +" \"Objetos em um programa devem ser substituíveis por instâncias de seus " +"subtipos\n" +" sem alterar a correção desse programa.\"\n" +"- [Princípio de Segregação de Interface " +"(ISP)](https://en.wikipedia.org/wiki/Interface_segregation_principle):\n" +" \"Muitas interfaces específicas do cliente são melhores do que uma de uso " +"geral\n" +" interface.\"\n" +"- [Princípio de Inversão de Dependência " +"(DIP)](https://en.wikipedia.org/wiki/Dependency_inversion_principle):\n" +" Deve-se \"depender de abstrações, [não] concreções\"." + +#: src\additional_resources/design-principles.md:25 +#, fuzzy +msgid "" +"## [DRY (Don’t Repeat " +"Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" +msgstr "" +"## [DRY (Don't Repeat " +"Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" + +#: src\additional_resources/design-principles.md:27 +#, fuzzy +msgid "" +"\"Every piece of knowledge must have a single, unambiguous, authoritative\n" +"representation within a system\"" +msgstr "" +"“Cada pedaço de conhecimento deve ter um único, inequívoco, autoritário\n" +"representação dentro de um sistema\"" + +#: src\additional_resources/design-principles.md:30 +#, fuzzy +msgid "## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" +msgstr "## [princípio KISS](https://en.wikipedia.org/wiki/KISS_principle)" + +#: 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 +#, fuzzy +msgid "## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" +msgstr "## [Lei de Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" + +#: src\additional_resources/design-principles.md:38 +#, fuzzy +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 "" +"um determinado objeto deve assumir o mínimo possível sobre a estrutura ou\n" +"propriedades de qualquer outra coisa (incluindo seus subcomponentes), de " +"acordo com\n" +"o princípio de \"ocultação de informações\"" + +#: src\additional_resources/design-principles.md:42 +#, fuzzy +msgid "" +"## [Design by contract " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" +msgstr "" +"## [Design por contrato " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" + +#: src\additional_resources/design-principles.md:44 +#, fuzzy +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 "" +"designers de software devem definir interface formal, precisa e verificável\n" +"especificações para componentes de software, que estendem a definição comum " +"de\n" +"tipos de dados abstratos com pré-condições, pós-condições e invariantes" + +#: src\additional_resources/design-principles.md:48 +#, fuzzy +msgid "" +"## " +"[Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" +msgstr "" +"## " +"[Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" + +#: src\additional_resources/design-principles.md:50 +#, fuzzy +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 "" +"agrupamento de dados com os métodos que operam nesses dados, ou a restrição\n" +"de acesso direto a alguns dos componentes de um objeto. O encapsulamento é " +"usado para\n" +"ocultar os valores ou estado de um objeto de dados estruturados dentro de " +"uma classe, evitando\n" +"acesso direto de partes não autorizadas a eles." + +#: src\additional_resources/design-principles.md:55 +#, fuzzy +msgid "" +"## " +"[Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" +msgstr "" +"## " +"[Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" + +#: src\additional_resources/design-principles.md:57 +#, fuzzy +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 "" +"“As funções não devem produzir efeitos colaterais abstratos... apenas " +"comandos\n" +"(procedimentos) serão permitidos para produzir efeitos colaterais.” " +"-Bertrand Meyer:\n" +"Construção de Software Orientado a Objetos" + +#: src\additional_resources/design-principles.md:61 +#, fuzzy +msgid "" +"## [Principle of least astonishment " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" +msgstr "" +"## [Princípio do menor espanto " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" + +#: src\additional_resources/design-principles.md:63 +#, fuzzy +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 "" +"um componente de um sistema deve se comportar de uma maneira que a maioria " +"dos usuários espera\n" +"comportar-se. O comportamento não deve surpreender ou surpreender os usuários" + +#: src\additional_resources/design-principles.md:66 +#, fuzzy +msgid "## Linguistic-Modular-Units" +msgstr "## Linguistic-Modular-Units" + +#: src\additional_resources/design-principles.md:68 +#, fuzzy +msgid "" +"“Modules must correspond to syntactic units in the language used.” - " +"Bertrand\n" +"Meyer: Object-Oriented Software Construction" +msgstr "" +"“Os módulos devem corresponder às unidades sintáticas da linguagem " +"utilizada.” -Bertrand\n" +"Meyer: Construção de Software Orientado a Objetos" + +#: src\additional_resources/design-principles.md:71 +#, fuzzy +msgid "## Self-Documentation" +msgstr "## Autodocumentação" + +#: src\additional_resources/design-principles.md:73 +#, fuzzy +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 "" +"“O projetista de um módulo deve se esforçar para tornar todas as informações " +"sobre o\n" +"parte do módulo do próprio módulo.” - Bertrand Meyer: Software Orientado a " +"Objetos\n" +"Construção" + +#: src\additional_resources/design-principles.md:77 +#, fuzzy +msgid "## Uniform-Access" +msgstr "## Uniform-Access" + +#: src\additional_resources/design-principles.md:79 +#, fuzzy +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 "" +"“Todos os serviços oferecidos por um módulo devem estar disponíveis por meio " +"de um\n" +"notação, que não revela se eles são implementados por meio de armazenamento " +"ou\n" +"através da computação”. - Bertrand Meyer: Construção de Software Orientado a " +"Objetos" + +#: src\additional_resources/design-principles.md:83 +#, fuzzy +msgid "## Single-Choice" +msgstr "## Escolha única" + +#: src\additional_resources/design-principles.md:85 +#, fuzzy +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 "" +"“Sempre que um sistema de software deve suportar um conjunto de " +"alternativas, uma e somente\n" +"um módulo no sistema deve conhecer sua lista exaustiva.” -Bertrand Meyer:\n" +"Construção de Software Orientado a Objetos" + +#: src\additional_resources/design-principles.md:89 +#, fuzzy +msgid "## Persistence-Closure" +msgstr "## Persistência-Fechamento" + +#: src\additional_resources/design-principles.md:91 +#, fuzzy +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 "" +"“Sempre que um mecanismo de armazenamento armazena um objeto, ele deve " +"armazenar com ele o\n" +"dependentes desse objeto. Sempre que um mecanismo de recuperação recupera " +"um\n" +"objeto armazenado anteriormente, ele também deve recuperar qualquer " +"dependente desse objeto\n" +"que ainda não foi recuperado.” - Bertrand Meyer: Software Orientado a " +"Objetos\n" +"Construção" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + From ed82042c511408fb656bea37b7df834d32e64441 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 9 Apr 2023 02:59:57 +0200 Subject: [PATCH 168/217] Add cloud-translated it translation as a starter (#361) --- po/it.po | 10280 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 10280 insertions(+) create mode 100644 po/it.po diff --git a/po/it.po b/po/it.po new file mode 100644 index 00000000..c1cbcc80 --- /dev/null +++ b/po/it.po @@ -0,0 +1,10280 @@ + +msgid "" +msgstr "" +"Project-Id-Version: Rust Design Patterns\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2023-04-08 21:51+0200\n" +"Last-Translator: \n" +"Language-Team: Italian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src\SUMMARY.md:3 +#, fuzzy +msgid "Introduction" +msgstr "introduzione" + +#: src\SUMMARY.md:4 +#, fuzzy +msgid "Translations" +msgstr "Traduzioni" + +#: src\SUMMARY.md:5 +#, fuzzy +msgid "Idioms" +msgstr "Idiomi" + +#: src\SUMMARY.md:6 +#, fuzzy +msgid "Use borrowed types for arguments" +msgstr "Usa i tipi presi in prestito per gli argomenti" + +#: src\SUMMARY.md:7 +#, fuzzy +msgid "Concatenating Strings with format!" +msgstr "Concatenare le stringhe con il formato!" + +#: src\SUMMARY.md:8 +#, fuzzy +msgid "Constructor" +msgstr "Costruttore" + +#: src\SUMMARY.md:9 +#, fuzzy +msgid "The Default Trait" +msgstr "Il tratto predefinito" + +#: src\SUMMARY.md:10 +#, fuzzy +msgid "Collections Are Smart Pointers" +msgstr "Le raccolte sono puntatori intelligenti" + +#: src\SUMMARY.md:11 +#, fuzzy +msgid "Finalisation in Destructors" +msgstr "Finalizzazione in Distruttori" + +#: src\SUMMARY.md:12 +#, fuzzy +msgid "mem::{take(_), replace(_)}" +msgstr "mem::{prendi(_), sostituisci(_)}" + +#: src\SUMMARY.md:13 +#, fuzzy +msgid "On-Stack Dynamic Dispatch" +msgstr "Invio dinamico in pila" + +#: src\SUMMARY.md:14 src\SUMMARY.md:40 +#, fuzzy +msgid "Foreign function interface (FFI)" +msgstr "Interfaccia per funzioni estere (FFI)" + +#: src\SUMMARY.md:15 +#, fuzzy +msgid "Idiomatic Errors" +msgstr "Errori idiomatici" + +#: src\SUMMARY.md:16 +#, fuzzy +msgid "Accepting Strings" +msgstr "Accettare stringhe" + +#: src\SUMMARY.md:17 +#, fuzzy +msgid "Passing Strings" +msgstr "Passare le stringhe" + +#: src\SUMMARY.md:18 +#, fuzzy +msgid "Iterating over an Option" +msgstr "Iterare su un'opzione" + +#: src\SUMMARY.md:19 +#, fuzzy +msgid "Pass Variables to Closure" +msgstr "Passa le variabili alla chiusura" + +#: src\SUMMARY.md:20 +#, fuzzy +msgid "Privacy For Extensibility" +msgstr "Privacy per l'estensibilità" + +#: src\SUMMARY.md:21 +#, fuzzy +msgid "Easy doc initialization" +msgstr "Facile inizializzazione dei documenti" + +#: src\SUMMARY.md:22 +#, fuzzy +msgid "Temporary mutability" +msgstr "Mutabilità temporanea" + +#: src\SUMMARY.md:23 +#, fuzzy +msgid "Return consumed arg on error" +msgstr "Restituisce l'argomento consumato in caso di errore" + +#: src\SUMMARY.md:25 +#, fuzzy +msgid "Design Patterns" +msgstr "Modelli di progettazione" + +#: src\SUMMARY.md:26 +#, fuzzy +msgid "Behavioural" +msgstr "Comportamentale" + +#: src\SUMMARY.md:27 +#, fuzzy +msgid "Command" +msgstr "Comando" + +#: src\SUMMARY.md:28 +#, fuzzy +msgid "Interpreter" +msgstr "Interprete" + +#: src\SUMMARY.md:29 +#, fuzzy +msgid "Newtype" +msgstr "Nuovo tipo" + +#: src\SUMMARY.md:30 +#, fuzzy +msgid "RAII Guards" +msgstr "Guardie Rai" + +#: src\SUMMARY.md:31 +#, fuzzy +msgid "Strategy" +msgstr "Strategia" + +#: src\SUMMARY.md:32 +#, fuzzy +msgid "Visitor" +msgstr "Visitatore" + +#: src\SUMMARY.md:33 +#, fuzzy +msgid "Creational" +msgstr "Creativo" + +#: src\SUMMARY.md:34 +#, fuzzy +msgid "Builder" +msgstr "Costruttore" + +#: src\SUMMARY.md:35 +#, fuzzy +msgid "Fold" +msgstr "Piega" + +#: src\SUMMARY.md:36 +#, fuzzy +msgid "Structural" +msgstr "Strutturale" + +#: src\SUMMARY.md:37 +#, fuzzy +msgid "Compose Structs" +msgstr "Componi strutture" + +#: src\SUMMARY.md:38 +#, fuzzy +msgid "Prefer Small Crates" +msgstr "Preferisci casse piccole" + +#: src\SUMMARY.md:39 +#, fuzzy +msgid "Contain unsafety in small modules" +msgstr "Contenere l'insicurezza in piccoli moduli" + +#: src\SUMMARY.md:41 +#, fuzzy +msgid "Object-Based APIs" +msgstr "API basate su oggetti" + +#: src\SUMMARY.md:42 +#, fuzzy +msgid "Type Consolidation into Wrappers" +msgstr "Digitare Consolidamento in wrapper" + +#: src\SUMMARY.md:44 +#, fuzzy +msgid "Anti-patterns" +msgstr "Anti-modelli" + +#: src\SUMMARY.md:45 +#, fuzzy +msgid "Clone to satisfy the borrow checker" +msgstr "Clona per soddisfare il controllore del prestito" + +#: src\SUMMARY.md:46 +#, fuzzy +msgid "#[deny(warnings)]" +msgstr "#[nega(avvisi)]" + +#: src\SUMMARY.md:47 +#, fuzzy +msgid "Deref Polymorphism" +msgstr "Polimorfismo di Deref" + +#: src\SUMMARY.md:49 +#, fuzzy +msgid "Functional Programming" +msgstr "Programmazione funzionale" + +#: src\SUMMARY.md:50 +#, fuzzy +msgid "Programming paradigms" +msgstr "Paradigmi di programmazione" + +#: src\SUMMARY.md:51 +#, fuzzy +msgid "Generics as Type Classes" +msgstr "Generici come classi di tipo" + +#: src\SUMMARY.md:52 +#, fuzzy +msgid "Lenses and Prisms" +msgstr "Lenti e prismi" + +#: src\SUMMARY.md:54 +#, fuzzy +msgid "Additional Resources" +msgstr "Risorse addizionali" + +#: src\SUMMARY.md:55 +#, fuzzy +msgid "Design principles" +msgstr "Principi di progettazione" + +#: src\intro.md:1 +#, fuzzy +msgid "# Introduction" +msgstr "# Introduzione" + +#: src\intro.md:3 +#, fuzzy +msgid "## Participation" +msgstr "## Partecipazione" + +#: src\intro.md:5 +#, fuzzy +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 "" +"Se sei interessato a contribuire a questo libro, dai un'occhiata al\n" +"[linee guida per il " +"contributo](https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md)." + +#: src\intro.md:8 +#, fuzzy +msgid "## Design patterns" +msgstr "## Modelli di progettazione" + +#: src\intro.md:10 +#, fuzzy +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 "" +"Nello sviluppo del software, spesso incontriamo problemi che condividono\n" +"somiglianze indipendentemente dall'ambiente in cui appaiono\n" +"i dettagli di implementazione sono cruciali per risolvere il compito a " +"portata di mano, potremmo\n" +"astratto da queste particolarità per trovare le pratiche comuni che\n" +"sono genericamente applicabili." + +#: src\intro.md:16 +#, fuzzy +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 "" +"I modelli di progettazione sono una raccolta di soluzioni riutilizzabili e " +"testate per\n" +"problemi ricorrenti in ingegneria. Rendono il nostro software più modulare,\n" +"manutenibile ed estensibile. Inoltre, questi modelli forniscono un comune\n" +"linguaggio per sviluppatori, rendendoli uno strumento eccellente per " +"efficaci\n" +"comunicazione durante la risoluzione dei problemi in team." + +#: src\intro.md:22 src\patterns/index.md:14 +#, fuzzy +msgid "## Design patterns in Rust" +msgstr "## Modelli di design in Rust" + +#: src\intro.md:24 +#, fuzzy +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 "" +"Rust non è orientato agli oggetti e la combinazione di tutte le sue " +"caratteristiche,\n" +"come elementi funzionali, un forte sistema di tipi e il controllo del " +"prestito,\n" +"lo rende unico.\n" +"Per questo motivo, i modelli di design di Rust variano rispetto ad altri\n" +"linguaggi di programmazione tradizionali orientati agli oggetti.\n" +"Ecco perché abbiamo deciso di scrivere questo libro. Ci auguriamo che ti " +"piaccia leggerlo!\n" +"Il libro è diviso in tre capitoli principali:" + +#: src\intro.md:32 +#, fuzzy +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 "" +"- [Idioms](./idioms/index.md): linee guida da seguire durante la codifica.\n" +" Sono le norme sociali della comunità.\n" +" Dovresti romperli solo se hai una buona ragione per farlo.\n" +"- [Design patterns](./patterns/index.md): metodi per risolvere problemi " +"comuni\n" +" durante la codifica.\n" +"- [Anti-patterns](./anti_patterns/index.md): metodi per risolvere problemi " +"comuni\n" +" durante la codifica.\n" +" Tuttavia, mentre i design pattern ci danno dei vantaggi,\n" +" gli anti-pattern creano più problemi." + +#: src\translations.md:1 +#, fuzzy +msgid "# Translations" +msgstr "# Traduzioni" + +#: src\translations.md:3 +#, fuzzy +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 "" +"Stiamo utilizzando " +"[mdbook-i18n-helper](https://github.com/google/mdbook-i18n-helpers).\n" +"Leggi come _aggiungere_ e _aggiornare_ le traduzioni nel [loro " +"repository](https://github.com/google/mdbook-i18n-helpers#creating-and-updating-translations)" + +#: src\translations.md:6 +#, fuzzy +msgid "## External translations" +msgstr "## Traduzioni esterne" + +#: src\translations.md:8 +#, fuzzy +msgid "- [简体中文](https://fomalhauthmj.github.io/patterns/)" +msgstr "- [简体中文](https://fomalhauthmj.github.io/patterns/)" + +#: src\translations.md:10 +#, fuzzy +msgid "" +"If you want to add a translation, please open an issue in the\n" +"[main repository](https://github.com/rust-unofficial/patterns)." +msgstr "" +"Se desideri aggiungere una traduzione, apri un problema nel file\n" +"[repository principale](https://github.com/rust-unofficial/patterns)." + +#: src\idioms/index.md:1 +#, fuzzy +msgid "# Idioms" +msgstr "# Idiomi" + +#: src\idioms/index.md:3 +#, fuzzy +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 "" +"[Idioms](https://en.wikipedia.org/wiki/Programming_idiom) sono comunemente " +"usati\n" +"stili, linee guida e modelli ampiamente concordati da una comunità.\n" +"Scrivere codice idiomatico consente ad altri sviluppatori di capire meglio " +"cos'è\n" +"accadendo." + +#: src\idioms/index.md:8 +#, fuzzy +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 "" +"Dopotutto, al computer interessa solo il codice macchina che viene generato\n" +"dal compilatore.\n" +"Invece, il codice sorgente è principalmente vantaggioso per lo " +"sviluppatore.\n" +"Quindi, visto che abbiamo questo livello di astrazione, perché non renderlo " +"più leggibile?" + +#: 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 +#, fuzzy +msgid "> Code is there for humans, not computers, to understand." +msgstr "> Il codice è lì per essere compreso dagli umani, non dai computer." + +#: src\idioms/coercion-arguments.md:1 +#, fuzzy +msgid "# Use borrowed types for arguments" +msgstr "# Usa i tipi presi in prestito per gli argomenti" + +#: 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 +#, fuzzy +msgid "## Description" +msgstr "## Descrizione" + +#: src\idioms/coercion-arguments.md:5 +#, fuzzy +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 "" +"L'utilizzo di un obiettivo di una coercizione deref può aumentare la " +"flessibilità del codice\n" +"quando si decide quale tipo di argomento utilizzare per un argomento di " +"funzione.\n" +"In questo modo, la funzione accetterà più tipi di input." + +#: src\idioms/coercion-arguments.md:9 +#, fuzzy +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 "" +"Questo non è limitato ai tipi di puntatore slice-able o fat.\n" +"In effetti, dovresti sempre preferire l'utilizzo del **tipo preso in " +"prestito**\n" +"**prendendo in prestito il tipo di proprietà**.\n" +"Ad esempio `&str` su `&String`, `&[T]` su `&Vec` o `&T` su `&Box`." + +#: src\idioms/coercion-arguments.md:14 +#, fuzzy +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 "" +"Utilizzando i tipi presi in prestito è possibile evitare livelli di " +"riferimento indiretto per tali istanze\n" +"dove il tipo di proprietà fornisce già uno strato di riferimento indiretto. " +"Ad esempio, a\n" +"\"Stringa\" ha uno strato di riferimento indiretto, quindi una \"&Stringa\" " +"avrà due strati di\n" +"indiretto. Possiamo evitarlo usando invece `&str` e lasciando `&String`\n" +"forzare a un `&str` ogni volta che la funzione viene invocata." + +#: 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 +#, fuzzy +msgid "## Example" +msgstr "## Esempio" + +#: src\idioms/coercion-arguments.md:22 +#, fuzzy +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 "" +"Per questo esempio, illustreremo alcune differenze per l'utilizzo di " +"`&String` come a\n" +"argomento della funzione rispetto all'utilizzo di un `&str`, ma le idee si " +"applicano anche all'utilizzo\n" +"`&Vec` rispetto all'utilizzo di un `&[T]` o all'utilizzo di un `&Box` " +"rispetto a un `&T`." + +#: src\idioms/coercion-arguments.md:26 +#, fuzzy +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 "" +"Considera un esempio in cui desideriamo determinare se una parola ne " +"contiene tre\n" +"vocali consecutive. Non abbiamo bisogno di possedere la stringa per " +"determinarlo, quindi noi\n" +"prenderà un riferimento." + +#: src\idioms/coercion-arguments.md:30 +#, fuzzy +msgid "The code might look something like this:" +msgstr "Il codice potrebbe essere simile a questo:" + +#: 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 +#, fuzzy +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 "" +"Funziona bene perché stiamo passando un tipo `&String` come parametro.\n" +"Se rimuoviamo i commenti sulle ultime due righe, l'esempio fallirà. Questo\n" +"è perché un tipo `&str` non costringerà a un tipo `&String`. Possiamo " +"risolvere questo problema\n" +"semplicemente modificando il tipo per il nostro argomento." + +#: src\idioms/coercion-arguments.md:67 +#, fuzzy +msgid "For instance, if we change our function declaration to:" +msgstr "Ad esempio, se cambiamo la nostra dichiarazione di funzione in:" + +#: src\idioms/coercion-arguments.md:69 +msgid "" +"```rust, ignore\n" +"fn three_vowels(word: &str) -> bool {\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:73 +#, fuzzy +msgid "then both versions will compile and print the same output." +msgstr "quindi entrambe le versioni compileranno e stamperanno lo stesso output." + +#: src\idioms/coercion-arguments.md:75 +msgid "" +"```bash\n" +"Ferris: false\n" +"Curious: true\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:80 +#, fuzzy +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 "" +"Ma aspetta, non è tutto! C'è di più su questa storia.\n" +"È probabile che tu possa dire a te stesso: non importa, non lo sarò mai\n" +"usando comunque una `&'static str` come input (come abbiamo fatto quando " +"abbiamo usato `\"Ferris\"`).\n" +"Anche ignorando questo esempio speciale, potresti comunque scoprire che " +"l'uso di `&str` lo farà\n" +"ti offre maggiore flessibilità rispetto all'utilizzo di una `&Stringa`." + +#: src\idioms/coercion-arguments.md:86 +#, fuzzy +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 "" +"Facciamo ora un esempio in cui qualcuno ci dà una frase, e noi vogliamo\n" +"determinare se una qualsiasi delle parole nella frase contiene tre vocali " +"consecutive.\n" +"Probabilmente dovremmo utilizzare la funzione che abbiamo già definito e " +"semplicemente\n" +"inserire ogni parola della frase." + +#: src\idioms/coercion-arguments.md:91 +#, fuzzy +msgid "An example of this could look like this:" +msgstr "Un esempio di questo potrebbe assomigliare a questo:" + +#: 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 +#, fuzzy +msgid "" +"Running this example using our function declared with an argument type " +"`&str`\n" +"will yield" +msgstr "" +"Eseguire questo esempio usando la nostra funzione dichiarata con un tipo di " +"argomento `&str`\n" +"cederà" + +#: src\idioms/coercion-arguments.md:124 +msgid "" +"```bash\n" +"curious has three consecutive vowels!\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:128 +#, fuzzy +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 "" +"Tuttavia, questo esempio non verrà eseguito quando la nostra funzione viene " +"dichiarata con an\n" +"tipo di argomento `&Stringa`. Questo perché le sezioni di stringa sono un " +"`&str` e non un\n" +"`&String` che richiederebbe la conversione di un'allocazione in `&String` " +"which\n" +"non è implicito, mentre la conversione da `String` a `&str` è economica e " +"implicita." + +#: 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 +#, fuzzy +msgid "## See also" +msgstr "## Guarda anche" + +#: src\idioms/coercion-arguments.md:135 +#, fuzzy +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 "" +"- [Riferimento al linguaggio Rust sulle coercizioni di " +"tipo](https://doc.rust-lang.org/reference/type-coercions.html)\n" +"- Per ulteriori discussioni su come gestire `String` e `&str` vedere\n" +" [questa serie di blog " +"(2015)](https://web.archive.org/web/20201112023149/https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html " +")\n" +" di Hermann J. Radtke III" + +#: src\idioms/concat-format.md:1 +#, fuzzy +msgid "# Concatenating strings with `format!`" +msgstr "# Concatenazione di stringhe con `format!`" + +#: src\idioms/concat-format.md:5 +#, fuzzy +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 "" +"È possibile creare stringhe usando i metodi `push` e `push_str` su a\n" +"mutabile `Stringa`, o usando il suo operatore `+`. Tuttavia, spesso è di " +"più\n" +"conveniente usare `format!`, specialmente dove c'è un misto di letterale e\n" +"stringhe non letterali." + +#: 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 +#, fuzzy +msgid "## Advantages" +msgstr "## Vantaggi" + +#: src\idioms/concat-format.md:27 +#, fuzzy +msgid "" +"Using `format!` is usually the most succinct and readable way to combine " +"strings." +msgstr "" +"Usare `format!` è di solito il modo più succinto e leggibile per combinare " +"le stringhe." + +#: 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 +#, fuzzy +msgid "## Disadvantages" +msgstr "## Svantaggi" + +#: src\idioms/concat-format.md:31 +#, fuzzy +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 "" +"Di solito non è il modo più efficiente per combinare le stringhe: una serie " +"di \"push\".\n" +"operazioni su una stringa mutabile è solitamente la più efficiente " +"(specialmente se il\n" +"la stringa è stata preallocata alla dimensione prevista)." + +#: src\idioms/ctor.md:1 +#, fuzzy +msgid "# Constructors\r" +msgstr "# Costruttori\r" + +#: src\idioms/ctor.md:3 src\idioms/rustdoc-init.md:3 +#, fuzzy +msgid "## Description\r" +msgstr "## Descrizione\r" + +#: src\idioms/ctor.md:5 +#, fuzzy +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 "" +"Rust non ha costruttori come costrutto del linguaggio. Invece il\r\n" +"convenzione è usare una [funzione associata][funzione associata] `new` per " +"creare un oggetto:" + +#: 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 +#, fuzzy +msgid "## Default Constructors\r" +msgstr "## Costruttori predefiniti\r" + +#: src\idioms/ctor.md:37 +#, fuzzy +msgid "" +"Rust supports default constructors with the [`Default`][std-default] trait:" +msgstr "" +"Rust supporta i costruttori predefiniti con il tratto " +"[`Default`][std-default]:" + +#: 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 +#, fuzzy +msgid "" +"`Default` can also be derived if all types of all fields implement " +"`Default`,\r\n" +"like they do with `Second`:" +msgstr "" +"`Default` può anche essere derivato se tutti i tipi di tutti i campi " +"implementano `Default`,\r\n" +"come fanno con `Secondo`:" + +#: 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 +#, fuzzy +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 "" +"**Nota:** è comune e previsto che i tipi implementino entrambi\r\n" +"`Default` e un costruttore `new` vuoto. `new` è il costruttore\r\n" +"convenzione in Rust e gli utenti si aspettano che esista, quindi se lo è\r\n" +"ragionevole che il costruttore di base non accetti argomenti, allora it\r\n" +"dovrebbe, anche se è funzionalmente identico a default." + +#: src\idioms/ctor.md:97 +#, fuzzy +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 "" +"**Suggerimento:** il vantaggio di implementare o derivare `Default` è che il " +"tuo tipo\r\n" +"ora può essere utilizzato dove è richiesta un'implementazione `Default`, " +"soprattutto,\r\n" +"qualsiasi delle [funzioni `*or_default` nella libreria " +"standard][std-or-default]." + +#: src\idioms/ctor.md:101 +#, fuzzy +msgid "## See also\r" +msgstr "## Guarda anche\r" + +#: src\idioms/ctor.md:103 +#, fuzzy +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 "" +"- L'[idioma predefinito](default.md) per una descrizione più approfondita " +"del file\r\n" +" Tratto `Predefinito`.\r\n" +"\r\n" +"- Il [modello builder](../patterns/creational/builder.md) per la " +"costruzione\r\n" +" oggetti in cui sono presenti più configurazioni.\r\n" +"\r\n" +"- [Linee guida API/C-COMMON-TRAITS][Linee guida API/C-COMMON-TRAITS] per\r\n" +" implementando entrambi, `Default` e `new`.\r\n" +"\r" + +#: src\idioms/default.md:1 +#, fuzzy +msgid "# The `Default` Trait" +msgstr "# Il tratto `Predefinito`" + +#: 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 +#, fuzzy +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 "" +"Non solo i contenitori a un elemento come `Cow`, `Box` o `Arc` implementano\n" +"`Default` per i tipi `Default` contenuti, si può automaticamente\n" +"`#[derive(Default)]` per struct i cui campi lo implementano tutti, quindi " +"more\n" +"i tipi implementano `Default`, più diventa utile." + +#: src\idioms/default.md:16 +#, fuzzy +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 "" +"D'altra parte, i costruttori possono prendere più argomenti, mentre il\n" +"Il metodo `default()` no. Possono anche esserci più costruttori con\n" +"nomi diversi, ma può esserci solo un'implementazione `Default` per tipo." + +#: 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 +#, fuzzy +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 "" +"- L'idioma [costruttore] è un altro modo per generare istanze che possono o " +"possono\n" +" non essere \"predefinito\"\n" +"- La documentazione [`Default`] (scorrere verso il basso per l'elenco degli " +"implementatori)\n" +"- [`Opzione::unwrap_or_default()`]\n" +"- [`deriva(nuovo)`]" + +#: src\idioms/deref.md:1 +#, fuzzy +msgid "# Collections are smart pointers" +msgstr "# Le raccolte sono puntatori intelligenti" + +#: src\idioms/deref.md:5 +#, fuzzy +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 "" +"Usa [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\n" +"tratto per trattare le raccolte come puntatori intelligenti, offrendo la " +"proprietà\n" +"e viste prese in prestito dei dati." + +#: 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 +#, fuzzy +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 "" +"Un `Vec` è una raccolta proprietaria di `T`, mentre una slice (`&[T]`) è " +"un oggetto preso in prestito\n" +"raccolta di `T`s. L'implementazione di \"Deref\" per \"Vec\" consente la " +"dereferenziazione implicita\n" +"da `&Vec` a `&[T]` e include la relazione nell'auto-derefencing\n" +"ricerche. La maggior parte dei metodi che potresti aspettarti di essere " +"implementati per `Vec`s lo sono invece\n" +"implementato per le fette." + +#: src\idioms/deref.md:34 +#, fuzzy +msgid "Also `String` and `&str` have a similar relation." +msgstr "Anche `String` e `&str` hanno una relazione simile." + +#: 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 +#, fuzzy +msgid "## Motivation" +msgstr "## Motivazione" + +#: src\idioms/deref.md:38 +#, fuzzy +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 "" +"La proprietà e il prestito sono aspetti chiave del linguaggio Rust. " +"Strutture dati\n" +"deve tenere conto di queste semantiche correttamente per dare un buon " +"utente\n" +"esperienza. Quando si implementa una struttura dati che possiede i suoi " +"dati, offrendo a\n" +"vista presa in prestito di tali dati consente API più flessibili." + +#: src\idioms/deref.md:45 +#, fuzzy +msgid "" +"Most methods can be implemented only for the borrowed view, they are then\n" +"implicitly available for the owning view." +msgstr "" +"La maggior parte dei metodi può essere implementata solo per la vista presa " +"in prestito, allora lo sono\n" +"implicitamente disponibile per la vista proprietaria." + +#: src\idioms/deref.md:48 +#, fuzzy +msgid "Gives clients a choice between borrowing or taking ownership of data." +msgstr "" +"Offre ai clienti la scelta tra prendere in prestito o assumere la proprietà " +"dei dati." + +#: src\idioms/deref.md:52 +#, fuzzy +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 "" +"I metodi e i tratti disponibili solo tramite dereferenziazione non vengono " +"presi in considerazione\n" +"durante il controllo dei limiti, quindi programmazione generica con " +"strutture di dati che utilizzano this\n" +"pattern può diventare complesso (vedi i tratti `Borrow` e `AsRef`, ecc.)." + +#: 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 +#, fuzzy +msgid "## Discussion" +msgstr "## Discussione" + +#: src\idioms/deref.md:58 +#, fuzzy +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 "" +"I puntatori intelligenti e le raccolte sono analoghi: un puntatore " +"intelligente punta a un singolo\n" +"oggetto, mentre una raccolta punta a molti oggetti. Dal punto di vista di\n" +"il sistema di tipo, c'è poca differenza tra i due. Una collezione possiede\n" +"i suoi dati se l'unico modo per accedere a ciascun dato è attraverso la " +"raccolta e il\n" +"collection è responsabile della cancellazione dei dati (anche in caso di " +"shared\n" +"proprietà, potrebbe essere appropriato un qualche tipo di visione presa in " +"prestito). Se una collezione possiede\n" +"suoi dati, di solito è utile fornire una vista dei dati presi in prestito in " +"modo che\n" +"può essere referenziato più volte." + +#: src\idioms/deref.md:67 +#, fuzzy +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 "" +"La maggior parte dei puntatori intelligenti (ad esempio, `Foo`) " +"implementano `Deref`. Tuttavia,\n" +"le collezioni di solito fanno riferimento a un tipo personalizzato. `[T]` e " +"`str` ne hanno alcuni\n" +"supporto linguistico, ma nel caso generale questo non è necessario. `Foo` " +"può\n" +"implementa `Deref>` dove `Bar` è un tipo dimensionato " +"dinamicamente e\n" +"`&Bar` è una vista presa in prestito dei dati in `Foo`." + +#: src\idioms/deref.md:73 +#, fuzzy +msgid "" +"Commonly, ordered collections will implement `Index` for `Range`s to " +"provide\n" +"slicing syntax. The target will be the borrowed view." +msgstr "" +"Comunemente, le raccolte ordinate implementeranno `Index` per `Range`s da " +"fornire\n" +"sintassi per affettare. L'obiettivo sarà la vista presa in prestito." + +#: src\idioms/deref.md:78 +#, fuzzy +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 "" +"- [Deref polimorfismo anti-pattern](../anti_patterns/deref.md).\n" +"- [Documentazione per il tratto " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\idioms/dtor-finally.md:1 +#, fuzzy +msgid "# Finalisation in destructors" +msgstr "# Finalizzazione nei distruttori" + +#: src\idioms/dtor-finally.md:5 +#, fuzzy +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 "" +"Rust non fornisce l'equivalente dei blocchi `finally` - codice che sarà\n" +"eseguito indipendentemente da come si esce da una funzione. Invece, il " +"distruttore di un oggetto può farlo\n" +"essere utilizzato per eseguire il codice che deve essere eseguito prima " +"dell'uscita." + +#: 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 +#, fuzzy +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 "" +"Se una funzione ha più punti di ritorno, l'esecuzione del codice all'uscita " +"diventa\n" +"difficile e ripetitivo (e quindi soggetto a bug). Questo è particolarmente " +"vero dove\n" +"return è implicito a causa di una macro. Un caso comune è l'operatore `?` " +"which\n" +"restituisce se il risultato è \"Err\", ma continua se è \"Ok\". `?` è usato " +"come\n" +"un meccanismo di gestione delle eccezioni, ma a differenza di Java (che ha " +"\"finalmente\"), c'è\n" +"non c'è modo di programmare l'esecuzione del codice sia nei casi normali che " +"in quelli eccezionali.\n" +"Anche il panico uscirà presto da una funzione." + +#: src\idioms/dtor-finally.md:44 +#, fuzzy +msgid "" +"Code in destructors will (nearly) always be run - copes with panics, early\n" +"returns, etc." +msgstr "" +"Il codice nei distruttori verrà (quasi) sempre eseguito - affronta il " +"panico, presto\n" +"ritorni, ecc." + +#: src\idioms/dtor-finally.md:49 +#, fuzzy +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 "" +"Non è garantito che i distruttori vengano eseguiti. Ad esempio, se esiste " +"un\n" +"ciclo infinito in una funzione o se l'esecuzione di una funzione si arresta " +"in modo anomalo prima dell'uscita.\n" +"Anche i distruttori non vengono eseguiti in caso di panico in una situazione " +"già in preda al panico\n" +"filo. Pertanto, non è possibile fare affidamento sui distruttori come " +"finalizzatori dove si trovano\n" +"assolutamente essenziale che avvenga la finalizzazione." + +#: src\idioms/dtor-finally.md:55 +#, fuzzy +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 "" +"Questo modello introduce un codice implicito difficile da notare. Lettura di " +"una funzione\n" +"non fornisce alcuna chiara indicazione dei distruttori da eseguire " +"all'uscita. Questo può fare\n" +"debug complicato." + +#: src\idioms/dtor-finally.md:59 +#, fuzzy +msgid "" +"Requiring an object and `Drop` impl just for finalisation is heavy on " +"boilerplate." +msgstr "" +"Richiedere un oggetto e \"Drop\" impl solo per la finalizzazione è pesante " +"sul boilerplate." + +#: src\idioms/dtor-finally.md:63 +#, fuzzy +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 "" +"C'è una certa sottigliezza su come memorizzare esattamente l'oggetto usato " +"come a\n" +"finalizzatore. Deve essere mantenuto in vita fino alla fine della funzione e " +"deve esserlo\n" +"distrutto. L'oggetto deve sempre essere un valore o un puntatore di " +"proprietà univoca (ad esempio,\n" +"`Box`). Se viene utilizzato un puntatore condiviso (come `Rc`), il " +"finalizzatore può farlo\n" +"essere mantenuto in vita oltre la durata della funzione. Per ragioni simili, " +"il\n" +"finalizzatore non deve essere spostato o restituito." + +#: src\idioms/dtor-finally.md:70 +#, fuzzy +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 "" +"Il finalizzatore deve essere assegnato in una variabile, altrimenti verrà " +"distrutto\n" +"immediatamente, piuttosto che quando esce dal campo di applicazione. Il nome " +"della variabile deve iniziare\n" +"con `_` se la variabile è usata solo come finalizzatore, altrimenti il " +"compilatore\n" +"avviserà che il finalizzatore non viene mai utilizzato. Tuttavia, non " +"chiamare la variabile\n" +"`_` senza suffisso - in tal caso verrà distrutto immediatamente." + +#: src\idioms/dtor-finally.md:76 +#, fuzzy +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 "" +"In Rust, i distruttori vengono eseguiti quando un oggetto esce dall'ambito. " +"Questo succede\n" +"se raggiungiamo la fine del blocco, c'è un ritorno anticipato o il " +"programma\n" +"panico. In preda al panico, Rust rimuove lo stack eseguendo i distruttori " +"per ciascuno\n" +"oggetto in ogni stack frame. Quindi, i distruttori vengono chiamati anche se " +"si verifica il panico\n" +"in una funzione che viene chiamata." + +#: src\idioms/dtor-finally.md:82 +#, fuzzy +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 "" +"Se un distruttore va nel panico mentre si rilassa, non c'è nessuna buona " +"azione da intraprendere, quindi Rust\n" +"interrompe immediatamente il thread, senza eseguire ulteriori distruttori. " +"Questo significa\n" +"che non è assolutamente garantito che i distruttori funzionino. Significa " +"anche che tu\n" +"devi prestare particolare attenzione ai tuoi distruttori per non farti " +"prendere dal panico, poiché potrebbe andarsene\n" +"risorse in uno stato imprevisto." + +#: src\idioms/dtor-finally.md:90 +#, fuzzy +msgid "[RAII guards](../patterns/behavioural/RAII.md)." +msgstr "[Guardie RAII](../patterns/behavioural/RAII.md)." + +#: src\idioms/mem-replace.md:1 +#, fuzzy +msgid "# `mem::{take(_), replace(_)}` to keep owned values in changed enums" +msgstr "" +"# `mem::{take(_), replace(_)}` per mantenere i valori posseduti nelle enum " +"modificate" + +#: src\idioms/mem-replace.md:5 +#, fuzzy +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 "" +"Supponiamo di avere un `&mut MyEnum` che ha (almeno) due varianti,\n" +"`A { nome: String, x: u8 }` e `B { nome: String }`. Ora vogliamo cambiare\n" +"`MyEnum::A` in una `B` se `x` è zero, mantenendo intatto `MyEnum::B`." + +#: src\idioms/mem-replace.md:9 +#, fuzzy +msgid "We can do this without cloning the `name`." +msgstr "Possiamo farlo senza clonare il `nome`." + +#: 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 +#, fuzzy +msgid "This also works with more variants:" +msgstr "Questo funziona anche con più varianti:" + +#: 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 +#, fuzzy +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 "" +"Quando lavoriamo con gli enum, potremmo voler cambiare un valore enum sul " +"posto, forse\n" +"ad un'altra variante. Questo di solito viene fatto in due fasi per mantenere " +"il prestito\n" +"correttore felice. Nella prima fase, osserviamo il valore esistente e " +"guardiamo\n" +"sue parti per decidere cosa fare dopo. Nella seconda fase possiamo " +"condizionalmente\n" +"modificare il valore (come nell'esempio precedente)." + +#: src\idioms/mem-replace.md:65 +#, fuzzy +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 "" +"Il controllo del prestito non ci consentirà di eliminare il \"nome\" " +"dell'enumerazione (perché\n" +"_qualcosa_ deve esserci.) Potremmo ovviamente nominare `.clone()` e inserire " +"il clone\n" +"nel nostro `MyEnum::B`, ma sarebbe un'istanza dell'anti-pattern [Clone per " +"soddisfare il controllo del prestito](../anti_patterns/borrow_clone.md). " +"Comunque, noi\n" +"può evitare l'allocazione extra cambiando `e` solo con un prestito mutabile." + +#: src\idioms/mem-replace.md:70 +#, fuzzy +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 "" +"`mem::take` ci permette di scambiare il valore, sostituendolo con il suo " +"valore predefinito,\n" +"e restituendo il valore precedente. Per \"Stringa\", il valore predefinito è " +"vuoto\n" +"`String`, che non deve essere allocato. Di conseguenza, otteniamo " +"l'originale\n" +"`nome` _come valore di proprietà_. Possiamo quindi avvolgerlo in un altro " +"enum." + +#: src\idioms/mem-replace.md:75 +#, fuzzy +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 "" +"**NOTA:** `mem::replace` è molto simile, ma ci permette di specificare cosa\n" +"sostituisci il valore con Un equivalente alla nostra riga `mem::take` " +"sarebbe\n" +"`mem::replace(name, String::new())`." + +#: src\idioms/mem-replace.md:79 +#, fuzzy +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 "" +"Nota, tuttavia, che se stiamo usando un'opzione `e vogliamo sostituirla\n" +"value con `None`, il metodo `take()` di `Option` fornisce un and\n" +"alternativa più idiomatica." + +#: src\idioms/mem-replace.md:85 +#, fuzzy +msgid "" +"Look ma, no allocation! Also you may feel like Indiana Jones while doing it." +msgstr "" +"Guarda mamma, nessuna allocazione! Inoltre potresti sentirti come Indiana " +"Jones mentre lo fai." + +#: src\idioms/mem-replace.md:89 +#, fuzzy +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 "" +"Questo diventa un po' prolisso. Sbagliare ripetutamente ti farà odiare il\n" +"controllore in prestito. Il compilatore potrebbe non riuscire a ottimizzare " +"il doppio archivio,\n" +"con conseguente riduzione delle prestazioni rispetto a ciò che faresti in " +"condizioni non sicure\n" +"le lingue." + +#: src\idioms/mem-replace.md:94 +#, fuzzy +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 "" +"Inoltre, il tipo che stai prendendo deve implementare il [tratto " +"`Default`](./default.md). Tuttavia, se il tipo con cui stai lavorando non lo " +"fa\n" +"implementarlo, puoi invece usare `mem::replace`." + +#: src\idioms/mem-replace.md:99 +#, fuzzy +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 "" +"Questo schema interessa solo Rust. Nelle lingue GC, prenderesti il\n" +"riferimento al valore per impostazione predefinita (e il GC terrà traccia " +"dei riferimenti), e in\n" +"altri linguaggi di basso livello come C avresti semplicemente alias il " +"puntatore e aggiustato le cose\n" +"Dopo." + +#: src\idioms/mem-replace.md:104 +#, fuzzy +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 "" +"Tuttavia, in Rust, dobbiamo fare un po' più di lavoro per farlo. Un valore " +"posseduto\n" +"potrebbe avere un solo proprietario, quindi per toglierlo dobbiamo " +"rimetterci qualcosa...\n" +"come Indiana Jones, sostituendo il manufatto con un sacco di sabbia." + +#: src\idioms/mem-replace.md:110 +#, fuzzy +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 "" +"Questo elimina [Clone per soddisfare il controllo del " +"prestito](../anti_patterns/borrow_clone.md)\n" +"anti-pattern in un caso specifico." + +#: src\idioms/on-stack-dyn-dispatch.md:1 +#, fuzzy +msgid "# On-Stack Dynamic Dispatch" +msgstr "# Invio dinamico in pila" + +#: src\idioms/on-stack-dyn-dispatch.md:5 +#, fuzzy +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 "" +"Possiamo spedire dinamicamente su più valori, tuttavia, per farlo, abbiamo " +"bisogno\n" +"per dichiarare più variabili per associare oggetti tipizzati in modo " +"diverso. Per estendere il\n" +"lifetime se necessario, possiamo usare l'inizializzazione condizionale " +"differita, come visto\n" +"sotto:" + +#: 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 +#, fuzzy +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 "" +"Rust monomorfizza il codice per impostazione predefinita. Ciò significa che " +"una copia del codice sarà\n" +"generato per ogni tipo con cui viene utilizzato e ottimizzato in modo " +"indipendente. Mentre questo\n" +"consente un codice molto veloce sul percorso caldo, inoltre gonfia il codice " +"in alcuni punti\n" +"dove le prestazioni non sono essenziali, costando così tempo di compilazione " +"e cache\n" +"utilizzo." + +#: src\idioms/on-stack-dyn-dispatch.md:45 +#, fuzzy +msgid "" +"Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " +"ask\n" +"for it." +msgstr "" +"Fortunatamente, Rust ci consente di utilizzare l'invio dinamico, ma dobbiamo " +"chiedere esplicitamente\n" +"per questo." + +#: src\idioms/on-stack-dyn-dispatch.md:50 +#, fuzzy +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 "" +"Non è necessario allocare nulla nell'heap. Nemmeno noi ne abbiamo bisogno\n" +"inizializzare qualcosa che non useremo in seguito, né abbiamo bisogno di " +"monomorfizzare il\n" +"tutto il codice che segue per funzionare sia con `File` che con `Stdin`." + +#: src\idioms/on-stack-dyn-dispatch.md:56 +#, fuzzy +msgid "The code needs more moving parts than the `Box`-based version:" +msgstr "" +"Il codice richiede più parti mobili rispetto alla versione basata su `Box`:" + +#: 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 +#, fuzzy +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 "" +"I nuovi arrivati di Rust di solito impareranno che Rust richiede che tutte " +"le variabili siano\n" +"inizializzato _prima dell'uso_, quindi è facile trascurare il fatto che _non " +"utilizzato_\n" +"le variabili potrebbero essere non inizializzate. Rust lavora molto " +"duramente per garantire che ciò avvenga\n" +"funziona bene e solo i valori inizializzati vengono eliminati alla fine del " +"loro\n" +"scopo." + +#: src\idioms/on-stack-dyn-dispatch.md:76 +#, fuzzy +msgid "The example meets all the constraints Rust places on us:" +msgstr "L'esempio soddisfa tutti i vincoli che Rust ci impone:" + +#: src\idioms/on-stack-dyn-dispatch.md:78 +#, fuzzy +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 "" +"- Tutte le variabili vengono inizializzate prima di utilizzarle (in questo " +"caso prendendole in prestito).\n" +"- Ogni variabile contiene solo valori di un singolo tipo. Nel nostro " +"esempio, `stdin` è\n" +" di tipo `Stdin`, `file` è di tipo `File` e `readable` è di tipo `&mut dyn " +"Read`\n" +"- Ogni valore preso in prestito sopravvive a tutti i riferimenti presi in " +"prestito da esso" + +#: src\idioms/on-stack-dyn-dispatch.md:85 +#, fuzzy +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 "" +"- [Finalizzazione nei distruttori](dtor-finally.md) e\n" +" [Le guardie RAII](../patterns/behavioural/RAII.md) possono beneficiare di " +"uno stretto controllo su\n" +" vite.\n" +"- Per i riferimenti `Option<&T>` riempiti in modo condizionale di " +"riferimenti (mutabili), si può\n" +" inizializzare un `Option` direttamente e utilizzare il suo metodo " +"[`.as_ref()`] per ottenere un\n" +" riferimento facoltativo." + +#: src\idioms/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Idioms" +msgstr "# Idiomi FFI" + +#: src\idioms/ffi/intro.md:3 +#, fuzzy +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 "" +"Scrivere il codice FFI è un intero corso in sé.\n" +"Tuttavia, ci sono diversi idiomi qui che possono fungere da puntatori ed " +"evitare\n" +"trappole per utenti inesperti di \"non sicuro\" Rust." + +#: src\idioms/ffi/intro.md:7 +#, fuzzy +msgid "This section contains idioms that may be useful when doing FFI." +msgstr "" +"Questa sezione contiene espressioni idiomatiche che possono essere utili " +"quando si fa FFI." + +#: src\idioms/ffi/intro.md:9 +#, fuzzy +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 "" +"1. [Errori idiomatici](./errors.md) - Gestione degli errori con codici " +"interi e\n" +" valori di ritorno sentinella (come i puntatori `NULL`)\n" +"\n" +"2. [Accepting Strings](./accepting-strings.md) con codice non sicuro minimo\n" +"\n" +"3. [Passing Strings](./passing-strings.md) alle funzioni FFI" + +#: src\idioms/ffi/errors.md:1 +#, fuzzy +msgid "# Error Handling in FFI" +msgstr "# Gestione degli errori in FFI" + +#: src\idioms/ffi/errors.md:5 +#, fuzzy +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 "" +"In lingue straniere come il C, gli errori sono rappresentati da codici di " +"ritorno.\n" +"Tuttavia, il sistema di tipi di Rust consente di avere informazioni sugli " +"errori molto più ricche\n" +"catturato e propagato attraverso un tipo completo." + +#: src\idioms/ffi/errors.md:9 +#, fuzzy +msgid "" +"This best practice shows different kinds of error codes, and how to expose " +"them\n" +"in a usable way:" +msgstr "" +"Questa procedura consigliata mostra diversi tipi di codici di errore e come " +"esporli\n" +"in modo utilizzabile:" + +#: src\idioms/ffi/errors.md:12 +#, fuzzy +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 "" +"1. Gli enum flat devono essere convertiti in numeri interi e restituiti come " +"codici.\n" +"2. Gli enum strutturati devono essere convertiti in un codice intero con un " +"errore di stringa\n" +" messaggio per i dettagli.\n" +"3. I tipi di errore personalizzati dovrebbero diventare \"trasparenti\", con " +"una rappresentazione C." + +#: 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 +#, fuzzy +msgid "## Code Example" +msgstr "## Esempio di codice" + +#: src\idioms/ffi/errors.md:19 +#, fuzzy +msgid "### Flat Enums" +msgstr "### Enumerazioni piatte" + +#: 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 +#, fuzzy +msgid "### Structured Enums" +msgstr "### Enumerazioni strutturate" + +#: 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 +#, fuzzy +msgid "### Custom Error Types" +msgstr "### Tipi di errore personalizzati" + +#: 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 +#, fuzzy +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 "" +"Ciò garantisce che la lingua straniera abbia un chiaro accesso alle " +"informazioni sugli errori\n" +"pur non compromettendo affatto l'API del codice Rust." + +#: src\idioms/ffi/errors.md:138 +#, fuzzy +msgid "" +"It's a lot of typing, and some types may not be able to be converted easily\n" +"to C." +msgstr "" +"È un sacco di digitazione e alcuni tipi potrebbero non essere convertiti " +"facilmente\n" +"a c." + +#: src\idioms/ffi/accepting-strings.md:1 +#, fuzzy +msgid "# Accepting Strings" +msgstr "# Accettazione di stringhe" + +#: src\idioms/ffi/accepting-strings.md:5 +#, fuzzy +msgid "" +"When accepting strings via FFI through pointers, there are two principles " +"that\n" +"should be followed:" +msgstr "" +"Quando si accettano stringhe tramite FFI tramite puntatori, esistono due " +"principi che\n" +"dovrebbe essere seguito:" + +#: src\idioms/ffi/accepting-strings.md:8 +#, fuzzy +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 "" +"1. Mantieni le stringhe straniere \"prese in prestito\", piuttosto che " +"copiarle direttamente.\n" +"2. Ridurre al minimo la complessità e il codice \"non sicuro\" coinvolti " +"nella conversione\n" +" da una stringa in stile C alle stringhe Rust native." + +#: src\idioms/ffi/accepting-strings.md:14 +#, fuzzy +msgid "" +"The strings used in C have different behaviours to those used in Rust, " +"namely:" +msgstr "" +"Le stringhe usate in C hanno comportamenti diversi da quelle usate in Rust, " +"ovvero:" + +#: src\idioms/ffi/accepting-strings.md:16 +#, fuzzy +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 "" +"- Le stringhe C hanno terminazione null mentre le stringhe Rust memorizzano " +"la loro lunghezza\n" +"- Le stringhe C possono contenere qualsiasi byte arbitrario diverso da zero " +"mentre le stringhe Rust devono esserlo\n" +" UTF-8\n" +"- Le stringhe C sono accessibili e manipolate usando operazioni di puntatore " +"`unsafe`\n" +" mentre le interazioni con le stringhe Rust passano attraverso metodi sicuri" + +#: src\idioms/ffi/accepting-strings.md:22 +#, fuzzy +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 "" +"La libreria standard di Rust viene fornita con gli equivalenti C di `String` " +"e `&str` di Rust\n" +"chiamate `CString` e `&CStr`, che ci permettono di evitare gran parte della " +"complessità\n" +"e il codice \"non sicuro\" coinvolto nella conversione tra stringhe C e " +"stringhe Rust." + +#: src\idioms/ffi/accepting-strings.md:26 +#, fuzzy +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 "" +"Il tipo `&CStr` ci permette anche di lavorare con dati presi in prestito, " +"ovvero di passaggio\n" +"stringhe tra Rust e C è un'operazione a costo zero." + +#: 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 +#, fuzzy +msgid "The example is is written to ensure that:" +msgstr "L'esempio è scritto per garantire che:" + +#: src\idioms/ffi/accepting-strings.md:72 +#, fuzzy +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 "" +"1. Il blocco \"non sicuro\" è il più piccolo possibile.\n" +"2. Il puntatore con una durata \"non tracciata\" diventa un condiviso " +"\"tracciato\".\n" +" riferimento" + +#: src\idioms/ffi/accepting-strings.md:76 +#, fuzzy +msgid "Consider an alternative, where the string is actually copied:" +msgstr "" +"Considera un'alternativa, in cui la stringa viene effettivamente copiata:" + +#: 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 +#, fuzzy +msgid "This code in inferior to the original in two respects:" +msgstr "Questo codice è inferiore all'originale sotto due aspetti:" + +#: src\idioms/ffi/accepting-strings.md:122 +#, fuzzy +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 "" +"1. C'è molto più codice \"non sicuro\" e, cosa più importante, più " +"invarianti\n" +" deve sostenere.\n" +"2. A causa dell'ampia aritmetica richiesta, c'è un bug in questa versione\n" +" che causa il \"comportamento indefinito\" di Rust." + +#: src\idioms/ffi/accepting-strings.md:127 +#, fuzzy +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 "" +"Il bug qui è un semplice errore nell'aritmetica del puntatore: la stringa è " +"stata copiata,\n" +"tutti i byte `msg_len` di esso. Tuttavia, il terminatore \"NUL\" alla fine " +"non lo era." + +#: src\idioms/ffi/accepting-strings.md:130 +#, fuzzy +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 "" +"Il vettore aveva quindi la sua dimensione _impostata_ sulla lunghezza della " +"_stringa imbottita zero_ --\n" +"piuttosto che _ridimensionato_ ad esso, che avrebbe potuto aggiungere uno " +"zero alla fine.\n" +"Di conseguenza, l'ultimo byte nel vettore è memoria non inizializzata.\n" +"Quando \"CString\" viene creato nella parte inferiore del blocco, viene " +"letto il file\n" +"Il vettore causerà un `comportamento indefinito`!" + +#: src\idioms/ffi/accepting-strings.md:136 +#, fuzzy +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 "" +"Come molti di questi problemi, questo sarebbe un problema difficile da " +"rintracciare.\n" +"A volte andava nel panico perché la stringa non era \"UTF-8\", a volte sì\n" +"metti un carattere strano alla fine della stringa, a volte sarebbe solo\n" +"crollare completamente." + +#: src\idioms/ffi/accepting-strings.md:143 +#: src\idioms/ffi/passing-strings.md:105 +#, fuzzy +msgid "None?" +msgstr "Nessuno?" + +#: src\idioms/ffi/passing-strings.md:1 +#, fuzzy +msgid "# Passing Strings" +msgstr "# Passaggio di stringhe" + +#: src\idioms/ffi/passing-strings.md:5 +#, fuzzy +msgid "" +"When passing strings to FFI functions, there are four principles that should " +"be\n" +"followed:" +msgstr "" +"Quando si passano stringhe alle funzioni FFI, ci sono quattro principi che " +"dovrebbero essere\n" +"seguito:" + +#: src\idioms/ffi/passing-strings.md:8 +#, fuzzy +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 "" +"1. Aumentare il più possibile la durata delle stringhe possedute.\n" +"2. Ridurre al minimo il codice \"non sicuro\" durante la conversione.\n" +"3. Se il codice C può modificare i dati della stringa, utilizzare \"Vec\" " +"invece di \"CString\".\n" +"4. A meno che l'API della funzione esterna non lo richieda, la proprietà " +"della stringa\n" +" non deve essere trasferito al chiamato." + +#: src\idioms/ffi/passing-strings.md:16 +#, fuzzy +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 "" +"Rust ha il supporto integrato per le stringhe in stile C con i suoi " +"`CString` e `CStr`\n" +"tipi. Tuttavia, ci sono diversi approcci che si possono adottare con " +"stringhe che\n" +"vengono inviati a una chiamata di funzione esterna da una funzione Rust." + +#: src\idioms/ffi/passing-strings.md:20 +#, fuzzy +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 "" +"La migliore pratica è semplice: usa `CString` in modo tale da minimizzare\n" +"codice \"non sicuro\". Tuttavia, un avvertimento secondario è quello\n" +"_l'oggetto deve vivere abbastanza a lungo_, il che significa che la durata " +"dovrebbe essere massimizzata.\n" +"Inoltre, la documentazione spiega che \"round-tripping\" a `CString` after\n" +"la modifica è UB, quindi in tal caso è necessario ulteriore lavoro." + +#: 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 +#, fuzzy +msgid "The example is written in a way to ensure that:" +msgstr "L'esempio è scritto in modo da garantire che:" + +#: src\idioms/ffi/passing-strings.md:72 +#, fuzzy +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 "" +"1. Il blocco \"non sicuro\" è il più piccolo possibile.\n" +"2. Il `CString` vive abbastanza a lungo.\n" +"3. Gli errori con i typecast vengono sempre propagati quando possibile." + +#: src\idioms/ffi/passing-strings.md:76 +#, fuzzy +msgid "" +"A common mistake (so common it's in the documentation) is to not use the\n" +"variable in the first block:" +msgstr "" +"Un errore comune (così comune è nella documentazione) è non usare il file\n" +"variabile nel primo blocco:" + +#: 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 +#, fuzzy +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 "" +"Questo codice si tradurrà in un puntatore penzolante, perché la durata del " +"file\n" +"`CString` non viene esteso dalla creazione del puntatore, a differenza di un " +"riferimento\n" +"creato." + +#: src\idioms/ffi/passing-strings.md:98 +#, fuzzy +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 "" +"Un altro problema spesso sollevato è che l'inizializzazione di un vettore 1k " +"di\n" +"zeri è \"lento\". Tuttavia, le versioni recenti di Rust lo ottimizzano " +"effettivamente\n" +"particolare macro a una chiamata a `zmalloc`, il che significa che è veloce " +"quanto l'operazione\n" +"la capacità del sistema di restituire la memoria azzerata (che è abbastanza " +"veloce)." + +#: src\idioms/option-iter.md:1 +#, fuzzy +msgid "# Iterating over an `Option`" +msgstr "# Iterazione su una `Opzione`" + +#: src\idioms/option-iter.md:5 +#, fuzzy +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 "" +"`Option` può essere visto come un contenitore che contiene zero o uno\n" +"elemento. In particolare, implementa il tratto `IntoIterator`, e come tale\n" +"può essere utilizzato con codice generico che necessita di tale tipo." + +#: src\idioms/option-iter.md:9 src\patterns/structural/small-crates.md:34 +#: src\patterns/structural/unsafe-mods.md:22 +#, fuzzy +msgid "## Examples" +msgstr "## Esempi" + +#: src\idioms/option-iter.md:11 +#, fuzzy +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 "" +"Poiché `Option` implementa `IntoIterator`, può essere utilizzato come " +"argomento per\n" +"[`.extend()`](https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend):" + +#: 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 +#, fuzzy +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 "" +"Se devi aggiungere un'opzione alla fine di un iteratore esistente, puoi " +"farlo\n" +"passalo a " +"[`.chain()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain):" + +#: 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 +#, fuzzy +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 "" +"Nota che se \"Option\" è sempre \"Some\", allora è più idiomatico da usare\n" +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) sul\n" +"elemento invece." + +#: src\idioms/option-iter.md:42 +#, fuzzy +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 "" +"Inoltre, poiché `Option` implementa `IntoIterator`, è possibile iterare\n" +"usando un ciclo `for`. Ciò equivale a confrontarlo con `if let Some(..)`,\n" +"e nella maggior parte dei casi dovresti preferire quest'ultimo." + +#: src\idioms/option-iter.md:48 +#, fuzzy +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 "" +"- [`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) è un\n" +" iteratore che restituisce esattamente un elemento. È un'alternativa più " +"leggibile a\n" +" `Alcuni(foo).into_iter()`.\n" +"\n" +"- " +"[`Iterator::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map)\n" +" è una versione di " +"[`Iterator::map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map),\n" +" specializzato per mappare funzioni che restituiscono `Opzione`.\n" +"\n" +"- Il crate [`ref_slice`](https://crates.io/crates/ref_slice) fornisce " +"funzioni\n" +" per convertire una `Opzione` in una fetta con zero o un elemento.\n" +"\n" +"- [Documentazione per " +"`Option`](https://doc.rust-lang.org/std/option/enum.Option.html)" + +#: src\idioms/pass-var-to-closure.md:1 +#, fuzzy +msgid "# Pass variables to closure" +msgstr "# Passa le variabili alla chiusura" + +#: src\idioms/pass-var-to-closure.md:5 +#, fuzzy +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 "" +"Per impostazione predefinita, le chiusure catturano il loro ambiente " +"prendendo in prestito. Oppure puoi usare\n" +"`move`-chiusura per spostare l'intero ambiente. Tuttavia, spesso vuoi " +"muoverti solo\n" +"alcune variabili alla chiusura, dagli una copia di alcuni dati, passalo per " +"riferimento o\n" +"eseguire qualche altra trasformazione." + +#: src\idioms/pass-var-to-closure.md:10 +#, fuzzy +msgid "Use variable rebinding in separate scope for that." +msgstr "Usa il rebinding variabile in un ambito separato per questo." + +#: src\idioms/pass-var-to-closure.md:14 +#, fuzzy +msgid "Use" +msgstr "Utilizzo" + +#: 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 +#, fuzzy +msgid "instead of" +msgstr "invece di" + +#: 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 +#, fuzzy +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 "" +"I dati copiati sono raggruppati insieme alla definizione di chiusura, quindi " +"il loro scopo è\n" +"più chiari, e verranno immediatamente eliminati anche se non vengono " +"consumati\n" +"per chiusura." + +#: src\idioms/pass-var-to-closure.md:54 +#, fuzzy +msgid "" +"Closure uses same variable names as surrounding code whether data are copied " +"or\n" +"moved." +msgstr "" +"La chiusura utilizza gli stessi nomi di variabile del codice circostante " +"indipendentemente dal fatto che i dati vengano copiati o\n" +"mosso." + +#: src\idioms/pass-var-to-closure.md:59 +#, fuzzy +msgid "Additional indentation of closure body." +msgstr "Rientro aggiuntivo del corpo della chiusura." + +#: src\idioms/priv-extend.md:1 +#, fuzzy +msgid "# `#[non_exhaustive]` and private fields for extensibility" +msgstr "# `#[non_esaustivo]` e campi privati per l'estensibilità" + +#: src\idioms/priv-extend.md:5 +#, fuzzy +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 "" +"Esiste un piccolo insieme di scenari in cui un autore di libreria potrebbe " +"voler aggiungere public\n" +"campi a una struttura pubblica o nuove varianti a un'enumerazione senza " +"andare all'indietro\n" +"Compatibilità." + +#: src\idioms/priv-extend.md:9 +#, fuzzy +msgid "Rust offers two solutions to this problem:" +msgstr "Rust offre due soluzioni a questo problema:" + +#: src\idioms/priv-extend.md:11 +#, fuzzy +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 "" +"- Usa `#[non_exhaustive]` sulle varianti `struct`s, `enum`s e `enum`.\n" +" Per un'ampia documentazione su tutti i luoghi in cui può essere " +"`#[non_esauriente]`\n" +" utilizzato, vedere [la " +"documentazione](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).\n" +"\n" +"- Puoi aggiungere un campo privato a una struttura per evitare che sia " +"diretta\n" +" istanziato o confrontato (vedi Alternativa)" + +#: 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 +#, fuzzy +msgid "## Alternative: `Private fields` for structs" +msgstr "## Alternativa: `Campi privati` per le strutture" + +#: src\idioms/priv-extend.md:59 +#, fuzzy +msgid "" +"`#[non_exhaustive]` only works across crate boundaries.\n" +"Within a crate, the private field method may be used." +msgstr "" +"\"#[non_exhaustive]\" funziona solo oltre i confini della cassa.\n" +"All'interno di una cassa, può essere utilizzato il metodo del campo privato." + +#: src\idioms/priv-extend.md:62 +#, fuzzy +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 "" +"L'aggiunta di un campo a una struttura è una modifica per lo più compatibile " +"con le versioni precedenti.\n" +"Tuttavia, se un client utilizza un modello per decostruire un'istanza " +"struct, essi\n" +"potrebbe nominare tutti i campi nella struttura e aggiungerne uno nuovo lo " +"interromperebbe\n" +"modello.\n" +"Il client potrebbe nominare alcuni campi e utilizzare `..` nel pattern, nel " +"qual caso aggiungendo\n" +"un altro campo è retrocompatibile.\n" +"Rendere privato almeno uno dei campi della struttura obbliga i client a " +"utilizzare quest'ultimo\n" +"forma di modelli, assicurando che la struttura sia a prova di futuro." + +#: src\idioms/priv-extend.md:71 +#, fuzzy +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 "" +"Lo svantaggio di questo approccio è che potrebbe essere necessario " +"aggiungere un file altrimenti non necessario\n" +"campo alla struttura.\n" +"Puoi usare il tipo `()` in modo che non ci sia sovraccarico di runtime e " +"anteporre `_` a\n" +"il nome del campo per evitare l'avviso di campo inutilizzato." + +#: 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 +#, fuzzy +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 "" +"Su `struct`s, `#[non_exhaustive]` consente di aggiungere ulteriori campi in " +"un modo all'indietro\n" +"modo compatibile.\n" +"Impedirà inoltre ai client di utilizzare il costruttore struct, anche se " +"tutti i file\n" +"i campi sono pubblici\n" +"Questo può essere utile, ma vale la pena considerare se _vuoi_ un campo " +"aggiuntivo\n" +"essere trovato dai client come un errore del compilatore piuttosto che " +"qualcosa che potrebbe essere nascosto\n" +"non scoperto." + +#: src\idioms/priv-extend.md:95 +#, fuzzy +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 "" +"`#[non_exhaustive]` può essere applicato anche alle varianti enum.\n" +"Una variante `#[non_exhaustive]` si comporta allo stesso modo di una " +"struttura `#[non_exhaustive]`." + +#: src\idioms/priv-extend.md:98 +#, fuzzy +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 "" +"Usalo deliberatamente e con cautela: incrementare la versione principale " +"durante l'aggiunta\n" +"campi o varianti è spesso un'opzione migliore.\n" +"\"#[non_exhaustive]\" può essere appropriato in scenari in cui stai " +"modellando un esterno\n" +"risorsa che potrebbe cambiare in modo non sincronizzato con la tua libreria, " +"ma non è uno scopo generale\n" +"attrezzo." + +#: src\idioms/priv-extend.md:104 +#, fuzzy +msgid "### Disadvantages" +msgstr "### Svantaggi" + +#: src\idioms/priv-extend.md:106 +#, fuzzy +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 "" +"`#[non_exhaustive]` può rendere il tuo codice molto meno ergonomico da " +"usare, specialmente quando\n" +"costretto a gestire varianti enum sconosciute.\n" +"Dovrebbe essere usato solo quando sono richiesti questi tipi di evoluzioni " +"**senza**\n" +"incrementando la versione principale." + +#: 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 +#, fuzzy +msgid "" +"- [RFC introducing #[non_exhaustive] attribute for enums and " +"structs](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" +msgstr "" +"- [RFC introduce l'attributo #[non_exhaustive] per enum e " +"struct](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" + +#: src\idioms/rustdoc-init.md:1 +#, fuzzy +msgid "# Easy doc initialization\r" +msgstr "# Facile inizializzazione dei documenti\r" + +#: src\idioms/rustdoc-init.md:5 +#, fuzzy +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 "" +"Se una struttura richiede uno sforzo significativo per l'inizializzazione " +"durante la scrittura di documenti, può esserlo\r\n" +"più veloce per avvolgere il tuo esempio con una funzione di supporto che " +"prende la struttura come un\r\n" +"discussione." + +#: src\idioms/rustdoc-init.md:9 +#, fuzzy +msgid "## Motivation\r" +msgstr "## Motivazione\r" + +#: src\idioms/rustdoc-init.md:11 +#, fuzzy +msgid "" +"Sometimes there is a struct with multiple or complicated parameters and " +"several\r\n" +"methods. Each of these methods should have examples." +msgstr "" +"A volte c'è una struttura con parametri multipli o complicati e diversi\r\n" +"metodi. Ognuno di questi metodi dovrebbe avere degli esempi." + +#: src\idioms/rustdoc-init.md:14 +#, fuzzy +msgid "For example:" +msgstr "Per esempio:" + +#: 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 +#, fuzzy +msgid "## Example\r" +msgstr "## Esempio\r" + +#: src\idioms/rustdoc-init.md:47 +#, fuzzy +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 "" +"Invece di digitare tutto questo boilerplate per creare una \"Connessione\" " +"e\r\n" +"`Request`, è più facile creare semplicemente una funzione di supporto per il " +"wrapping che accetta\r\n" +"loro come argomenti:" + +#: 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 +#, fuzzy +msgid "## Advantages\r" +msgstr "## Vantaggi\r" + +#: src\idioms/rustdoc-init.md:79 +#, fuzzy +msgid "This is much more concise and avoids repetitive code in examples." +msgstr "Questo è molto più conciso ed evita il codice ripetitivo negli esempi." + +#: src\idioms/rustdoc-init.md:81 +#, fuzzy +msgid "## Disadvantages\r" +msgstr "## Svantaggi\r" + +#: src\idioms/rustdoc-init.md:83 +#, fuzzy +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 "" +"Poiché l'esempio è in una funzione, il codice non verrà testato. Anche se lo " +"sarà ancora\r\n" +"controllato per assicurarsi che venga compilato durante l'esecuzione di un " +"`cargo test`. Quindi questo modello è\r\n" +"molto utile quando hai bisogno di `no_run`. Con questo, non è necessario " +"aggiungere `no_run`." + +#: src\idioms/rustdoc-init.md:87 +#, fuzzy +msgid "## Discussion\r" +msgstr "## Discussione\r" + +#: src\idioms/rustdoc-init.md:89 +#, fuzzy +msgid "If assertions are not required this pattern works well." +msgstr "Se le asserzioni non sono richieste, questo modello funziona bene." + +#: src\idioms/rustdoc-init.md:91 +#, fuzzy +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 "" +"Se lo sono, un'alternativa può essere quella di creare un metodo pubblico " +"per creare un helper\r\n" +"istanza che è annotata con `#[doc(hidden)]` (in modo che gli utenti non la " +"vedano).\r\n" +"Quindi questo metodo può essere chiamato all'interno di rustdoc perché fa " +"parte del file\r\n" +"API pubblica di crate." + +#: src\idioms/temporary-mutability.md:1 +#, fuzzy +msgid "# Temporary mutability" +msgstr "# Mutabilità temporanea" + +#: src\idioms/temporary-mutability.md:5 +#, fuzzy +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 "" +"Spesso è necessario preparare ed elaborare alcuni dati, ma poi i dati lo " +"sono\n" +"solo revisionata e mai modificata. L'intenzione può essere resa esplicita " +"ridefinendo\n" +"la variabile mutabile come immutabile." + +#: src\idioms/temporary-mutability.md:9 +#, fuzzy +msgid "" +"It can be done either by processing data within a nested block or by " +"redefining\n" +"the variable." +msgstr "" +"Può essere fatto elaborando i dati all'interno di un blocco nidificato o " +"ridefinendo\n" +"la variabile." + +#: src\idioms/temporary-mutability.md:14 +#, fuzzy +msgid "Say, vector must be sorted before usage." +msgstr "Supponiamo che il vettore debba essere ordinato prima dell'uso." + +#: src\idioms/temporary-mutability.md:16 +#, fuzzy +msgid "Using nested block:" +msgstr "Utilizzando il blocco annidato:" + +#: 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 +#, fuzzy +msgid "Using variable rebinding:" +msgstr "Utilizzo del rebinding variabile:" + +#: 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 +#, fuzzy +msgid "" +"Compiler ensures that you don't accidentally mutate data after some point." +msgstr "" +"Il compilatore garantisce di non modificare accidentalmente i dati dopo un " +"certo punto." + +#: src\idioms/temporary-mutability.md:44 +#, fuzzy +msgid "" +"Nested block requires additional indentation of block body.\n" +"One more line to return data from block or redefine variable." +msgstr "" +"Il blocco annidato richiede un rientro aggiuntivo del corpo del blocco.\n" +"Un'altra riga per restituire i dati dal blocco o ridefinire la variabile." + +#: src\idioms/return-consumed-arg-on-error.md:1 +#, fuzzy +msgid "# Return consumed argument on error" +msgstr "# Restituisce l'argomento consumato in caso di errore" + +#: src\idioms/return-consumed-arg-on-error.md:5 +#, fuzzy +msgid "" +"If a fallible function consumes (moves) an argument, return that argument " +"back inside\n" +"an error." +msgstr "" +"Se una funzione fallibile consuma (sposta) un argomento, riporta " +"quell'argomento all'interno\n" +"un errore." + +#: 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 +#, fuzzy +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 "" +"In caso di errore potresti voler provare un modo alternativo o per\n" +"riprovare l'azione in caso di funzione non deterministica. Ma se " +"l'argomento\n" +"è sempre consumato, sei costretto a clonarlo ad ogni chiamata, quale\n" +"non è molto efficiente." + +#: src\idioms/return-consumed-arg-on-error.md:50 +#, fuzzy +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 "" +"La libreria standard utilizza questo approccio ad es. Metodo " +"`String::from_utf8`.\n" +"Quando viene fornito un vettore che non contiene UTF-8 valido, viene " +"visualizzato un `FromUtf8Error`\n" +"viene restituito.\n" +"Puoi recuperare il vettore originale usando il metodo " +"`FromUtf8Error::into_bytes`." + +#: src\idioms/return-consumed-arg-on-error.md:57 +#, fuzzy +msgid "Better performance because of moving arguments whenever possible." +msgstr "" +"Migliori prestazioni grazie allo spostamento degli argomenti quando " +"possibile." + +#: src\idioms/return-consumed-arg-on-error.md:61 +#, fuzzy +msgid "Slightly more complex error types." +msgstr "Tipi di errore leggermente più complessi." + +#: src\patterns/index.md:1 +#, fuzzy +msgid "# Design Patterns" +msgstr "# Modelli di progettazione" + +#: src\patterns/index.md:3 +#, fuzzy +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 "" +"[Modelli di " +"progettazione](https://en.wikipedia.org/wiki/Software_design_pattern) lo " +"sono\n" +"\"soluzioni generali riutilizzabili a un problema che si verifica " +"comunemente all'interno di un dato\n" +"contesto nella progettazione del software\". I modelli di progettazione sono " +"un ottimo modo per descrivere il\n" +"cultura di un linguaggio di programmazione. I modelli di progettazione sono " +"molto specifici della lingua -\n" +"quello che è uno schema in una lingua potrebbe non essere necessario in " +"un'altra a causa di a\n" +"caratteristica della lingua, o impossibile da esprimere a causa di una " +"caratteristica mancante." + +#: src\patterns/index.md:10 +#, fuzzy +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 "" +"Se abusati, i design pattern possono aggiungere inutili complessità ai " +"programmi.\n" +"Tuttavia, sono un ottimo modo per condividere conoscenze di livello " +"intermedio e avanzato\n" +"su un linguaggio di programmazione." + +#: src\patterns/index.md:16 +#, fuzzy +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 "" +"Rust ha molte caratteristiche uniche. Queste funzionalità ci danno un grande " +"vantaggio rimuovendo\n" +"intere classi di problemi. Alcuni di essi sono anche modelli _unici_ di Rust." + +#: src\patterns/index.md:19 +#, fuzzy +msgid "## YAGNI" +msgstr "## YAGNI" + +#: src\patterns/index.md:21 +#, fuzzy +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 "" +"YAGNI è un acronimo che sta per `You Are not Going to Need It`.\n" +"È un principio di progettazione software fondamentale da applicare durante " +"la scrittura del codice." + +#: src\patterns/index.md:24 +#, fuzzy +msgid "> The best code I ever wrote was code I never wrote." +msgstr "" +"> Il miglior codice che abbia mai scritto è stato un codice che non ho mai " +"scritto." + +#: src\patterns/index.md:26 +#, fuzzy +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 "" +"Se applichiamo YAGNI ai modelli di design, vediamo che le caratteristiche di " +"Rust ce lo consentono\n" +"buttare via molti modelli. Ad esempio, non è necessario il [modello " +"strategico](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"in Rust perché possiamo semplicemente usare " +"[traits](https://doc.rust-lang.org/book/traits.html)." + +#: src\patterns/behavioural/intro.md:1 +#, fuzzy +msgid "# Behavioural Patterns" +msgstr "# Modelli comportamentali" + +#: src\patterns/behavioural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" + +#: src\patterns/behavioural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that identify common communication patterns among " +"objects.\n" +"> By doing so, these patterns increase flexibility in carrying out " +"communication." +msgstr "" +"> Modelli di design che identificano modelli di comunicazione comuni tra gli " +"oggetti.\n" +"> In tal modo, questi modelli aumentano la flessibilità nell'effettuare la " +"comunicazione." + +#: src\patterns/behavioural/command.md:1 +#, fuzzy +msgid "# Command" +msgstr "# Comando" + +#: src\patterns/behavioural/command.md:5 +#, fuzzy +msgid "" +"The basic idea of the Command pattern is to separate out actions into its " +"own\n" +"objects and pass them as parameters." +msgstr "" +"L'idea di base del modello di comando è separare le azioni nelle proprie\n" +"oggetti e passarli come parametri." + +#: src\patterns/behavioural/command.md:10 +#, fuzzy +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 "" +"Supponiamo di avere una sequenza di azioni o transazioni incapsulate come " +"oggetti.\n" +"Vogliamo che queste azioni o comandi vengano eseguiti o richiamati in un " +"certo ordine in un secondo momento\n" +"in tempi diversi. Questi comandi possono anche essere attivati a seguito di " +"qualche evento.\n" +"Ad esempio, quando un utente preme un pulsante o all'arrivo di un pacchetto " +"di dati.\n" +"Inoltre, questi comandi potrebbero essere annullabili. Questo può tornare " +"utile per\n" +"operazioni di un editore. Potremmo voler memorizzare i log dei comandi " +"eseguiti in modo che\n" +"potremmo riapplicare le modifiche in un secondo momento se il sistema va in " +"crash." + +#: src\patterns/behavioural/command.md:20 +#, fuzzy +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 "" +"Definisci due operazioni di database \"crea tabella\" e \"aggiungi campo\". " +"Ognuno di questi\n" +"operations è un comando che sa come annullare il comando, ad esempio `drop " +"table`\n" +"e `rimuovi campo`. Quando un utente richiama un'operazione di migrazione del " +"database, each\n" +"Il comando viene eseguito nell'ordine definito e quando l'utente richiama il " +"rollback\n" +"operazione allora l'intera serie di comandi viene richiamata in ordine " +"inverso." + +#: src\patterns/behavioural/command.md:26 +#, fuzzy +msgid "## Approach: Using trait objects" +msgstr "## Approccio: utilizzo di oggetti tratto" + +#: src\patterns/behavioural/command.md:28 +#, fuzzy +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 "" +"Definiamo un tratto comune che incapsula il nostro comando con due " +"operazioni\n" +"`esegui` e `rollback`. Tutti i comandi `structs` devono implementare questa " +"caratteristica." + +#: 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 +#, fuzzy +msgid "## Approach: Using function pointers" +msgstr "## Approccio: utilizzo dei puntatori di funzione" + +#: src\patterns/behavioural/command.md:97 +#, fuzzy +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 "" +"Potremmo seguire un altro approccio creando ogni singolo comando come\n" +"una funzione diversa e memorizza i puntatori a funzione per richiamare " +"queste funzioni in un secondo momento\n" +"in un momento diverso. Poiché i puntatori di funzione implementano tutti e " +"tre i tratti `Fn`,\n" +"`FnMut` e `FnOnce` potremmo anche passare e memorizzare le chiusure invece " +"di\n" +"puntatori di funzione." + +#: 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 +#, fuzzy +msgid "## Approach: Using `Fn` trait objects" +msgstr "## Approccio: utilizzo di oggetti tratto `Fn`" + +#: src\patterns/behavioural/command.md:152 +#, fuzzy +msgid "" +"Finally, instead of defining a common command trait we could store\n" +"each command implementing the `Fn` trait separately in vectors." +msgstr "" +"Infine, invece di definire un tratto di comando comune, potremmo " +"memorizzare\n" +"ogni comando implementa il tratto `Fn` separatamente nei vettori." + +#: 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 +#, fuzzy +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 "" +"Se i nostri comandi sono piccoli e possono essere definiti come funzioni o " +"passati come chiusura\n" +"quindi l'utilizzo di puntatori a funzione potrebbe essere preferibile poiché " +"non sfrutta\n" +"invio dinamico. Ma se il nostro comando è un'intera struttura con un mucchio " +"di funzioni\n" +"e le variabili definite come modulo separato sarebbero allora utilizzando " +"gli oggetti tratto\n" +"più adatto. Un caso di applicazione può essere trovato in " +"[`actix`](https://actix.rs/),\n" +"che utilizza oggetti tratto quando registra una funzione di gestione per le " +"rotte.\n" +"In caso di utilizzo di oggetti tratto `Fn` possiamo creare e utilizzare " +"comandi nello stesso\n" +"modo come abbiamo usato in caso di puntatori a funzione." + +#: src\patterns/behavioural/command.md:214 +#, fuzzy +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 "" +"Come prestazioni, c'è sempre un compromesso tra prestazioni e codice\n" +"semplicità e organizzazione. L'invio statico offre prestazioni più veloci, " +"mentre\n" +"l'invio dinamico fornisce flessibilità quando strutturiamo la nostra " +"applicazione." + +#: src\patterns/behavioural/command.md:220 +#, fuzzy +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 "" +"- [Modello di comando](https://en.wikipedia.org/wiki/Command_pattern)\n" +"\n" +"- [Un altro esempio per il pattern " +"`command`](https://web.archive.org/web/20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" + +#: src\patterns/behavioural/interpreter.md:1 +#, fuzzy +msgid "# Interpreter" +msgstr "# Interprete" + +#: src\patterns/behavioural/interpreter.md:5 +#, fuzzy +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 "" +"Se un problema si verifica molto spesso e richiede passaggi lunghi e " +"ripetitivi per essere risolto\n" +"it, allora le istanze del problema potrebbero essere espresse in un " +"linguaggio semplice e un\n" +"oggetto interprete potrebbe risolverlo interpretando le frasi scritte in " +"questo\n" +"linguaggio semplice." + +#: src\patterns/behavioural/interpreter.md:10 +#, fuzzy +msgid "Basically, for any kind of problems we define:" +msgstr "In sostanza, per qualsiasi tipo di problema definiamo:" + +#: src\patterns/behavioural/interpreter.md:12 +#, fuzzy +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 "" +"- Una [lingua specifica del " +"dominio](https://en.wikipedia.org/wiki/Domain-specific_language),\n" +"- Una grammatica per questa lingua,\n" +"- Un interprete che risolve le istanze del problema." + +#: src\patterns/behavioural/interpreter.md:18 +#, fuzzy +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 "" +"Il nostro obiettivo è tradurre semplici espressioni matematiche in " +"espressioni postfisse\n" +"(o [notazione polacca " +"inversa](https://en.wikipedia.org/wiki/Reverse_Polish_notation))\n" +"Per semplicità, le nostre espressioni sono composte da dieci cifre `0`, ..., " +"`9` e due\n" +"operazioni `+`, `-`. Ad esempio, l'espressione \"2 + 4\" è tradotta in\n" +"`2 4 +`." + +#: src\patterns/behavioural/interpreter.md:24 +#, fuzzy +msgid "## Context Free Grammar for our problem" +msgstr "## Grammatica senza contesto per il nostro problema" + +#: src\patterns/behavioural/interpreter.md:26 +#, fuzzy +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 "" +"Il nostro compito è tradurre le espressioni infisse in postfisse. Definiamo " +"un contesto\n" +"grammatica libera per un insieme di espressioni infisse su `0`, ..., `9`, " +"`+` e `-`,\n" +"Dove:" + +#: src\patterns/behavioural/interpreter.md:30 +#, fuzzy +msgid "" +"- Terminal symbols: `0`, `...`, `9`, `+`, `-`\n" +"- Non-terminal symbols: `exp`, `term`\n" +"- Start symbol is `exp`\n" +"- And the following are production rules" +msgstr "" +"- Simboli terminali: `0`, `...`, `9`, `+`, `-`\n" +"- Simboli non terminali: `exp`, `term`\n" +"- Il simbolo di inizio è `exp`\n" +"- E le seguenti sono regole di produzione" + +#: 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 +#, fuzzy +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 "" +"**NOTA:** Questa grammatica dovrebbe essere ulteriormente trasformata a " +"seconda di cosa stiamo andando\n" +"a che fare con esso. Ad esempio, potremmo dover rimuovere la ricorsione a " +"sinistra. Per più\n" +"dettagli vedere [Compilers: Principles,Techniques, and " +"Tools](https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)\n" +"(alias Libro del Drago)." + +#: src\patterns/behavioural/interpreter.md:47 +#, fuzzy +msgid "## Solution" +msgstr "## Soluzione" + +#: src\patterns/behavioural/interpreter.md:49 +#, fuzzy +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 "" +"Implementiamo semplicemente un parser di discesa ricorsivo. Per semplicità, " +"il codice\n" +"va in panico quando un'espressione è sintatticamente errata (ad esempio " +"`2-34` o `2+5-`\n" +"sono errate secondo la definizione grammaticale)." + +#: 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 +#, fuzzy +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 "" +"Potrebbe esserci una percezione errata che il modello di progettazione di " +"Interpreter riguardi il design\n" +"grammatiche per linguaggi formali e implementazione di parser per queste " +"grammatiche.\n" +"In effetti, questo modello riguarda l'espressione di istanze problematiche " +"in modo più specifico\n" +"modo e implementando funzioni/classi/strutture che risolvono queste istanze " +"del problema.\n" +"Il linguaggio Rust ha `macro_rules!` che ci permettono di definire sintassi " +"e regole speciali\n" +"su come espandere questa sintassi nel codice sorgente." + +#: src\patterns/behavioural/interpreter.md:112 +#, fuzzy +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 "" +"Nell'esempio seguente creiamo un semplice `macro_rules!` che calcola\n" +"[Lunghezza euclidea](https://en.wikipedia.org/wiki/Euclidean_distance) di " +"`n`\n" +"vettori dimensionali. Scrivere `norma!(x,1,2)` potrebbe essere più facile da " +"esprimere e altro ancora\n" +"efficiente che comprimere `x,1,2` in un `Vec` e chiamare una funzione di " +"calcolo\n" +"la lunghezza." + +#: 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 +#, fuzzy +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 "" +"- [Modello " +"dell'interprete](https://en.wikipedia.org/wiki/Interpreter_pattern)\n" +"- [Grammatica senza " +"contesto](https://en.wikipedia.org/wiki/Context-free_grammar)\n" +"- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" + +#: src\patterns/behavioural/newtype.md:1 +#, fuzzy +msgid "# Newtype" +msgstr "# Nuovo tipo" + +#: src\patterns/behavioural/newtype.md:3 +#, fuzzy +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 "" +"Cosa succede se in alcuni casi vogliamo che un tipo si comporti in modo " +"simile a un altro tipo o\n" +"applicare alcuni comportamenti in fase di compilazione quando si utilizzano " +"solo alias di tipo\n" +"non essere abbastanza?" + +#: src\patterns/behavioural/newtype.md:7 +#, fuzzy +msgid "" +"For example, if we want to create a custom `Display` implementation for " +"`String`\n" +"due to security considerations (e.g. passwords)." +msgstr "" +"Ad esempio, se vogliamo creare un'implementazione `Display` personalizzata " +"per `String`\n" +"per motivi di sicurezza (ad es. password)." + +#: src\patterns/behavioural/newtype.md:10 +#, fuzzy +msgid "" +"For such cases we could use the `Newtype` pattern to provide **type " +"safety**\n" +"and **encapsulation**." +msgstr "" +"Per questi casi potremmo usare il modello `Newtype` per fornire **sicurezza " +"del tipo**\n" +"e **incapsulamento**." + +#: src\patterns/behavioural/newtype.md:15 +#, fuzzy +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 "" +"Usa una struttura di tupla con un singolo campo per creare un wrapper opaco " +"per un tipo.\n" +"Questo crea un nuovo tipo, piuttosto che un alias di un tipo (elementi " +"`type`)." + +#: 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 +#, fuzzy +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 "" +"La motivazione principale per i newtype è l'astrazione. Ti permette di " +"condividere\n" +"dettagli di implementazione tra i tipi controllando con precisione " +"l'interfaccia.\n" +"Usando un newtype piuttosto che esporre il tipo di implementazione come " +"parte di un\n" +"API, consente di modificare l'implementazione in modo compatibile con le " +"versioni precedenti." + +#: src\patterns/behavioural/newtype.md:63 +#, fuzzy +msgid "" +"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give\n" +"distinguishable `Miles` and `Kilometres`." +msgstr "" +"I newtype possono essere usati per distinguere le unità, ad esempio " +"avvolgendo `f64` per dare\n" +"distinguibili `Miglia` e `Chilometri`." + +#: src\patterns/behavioural/newtype.md:68 +#, fuzzy +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 "" +"I tipi wrapper e wrapper non sono compatibili con i tipi (al contrario di " +"using\n" +"`type`), quindi gli utenti del newtype non 'confonderanno' mai il wrapper e " +"il wrapper\n" +"tipi." + +#: src\patterns/behavioural/newtype.md:72 +#, fuzzy +msgid "Newtypes are a zero-cost abstraction - there is no runtime overhead." +msgstr "" +"I newtype sono un'astrazione a costo zero: non vi è alcun sovraccarico di " +"runtime." + +#: src\patterns/behavioural/newtype.md:74 +#, fuzzy +msgid "" +"The privacy system ensures that users cannot access the wrapped type (if " +"the\n" +"field is private, which it is by default)." +msgstr "" +"Il sistema di privacy garantisce che gli utenti non possano accedere al tipo " +"avvolto (se il file\n" +"campo è privato, che è per impostazione predefinita)." + +#: src\patterns/behavioural/newtype.md:79 +#, fuzzy +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 "" +"Lo svantaggio dei newtype (soprattutto rispetto agli alias di tipo) è che " +"esiste\n" +"non è un supporto linguistico speciale. Ciò significa che ci possono essere " +"_molti_ standard.\n" +"È necessario un metodo \"pass through\" per ogni metodo che si desidera " +"esporre sul file\n" +"tipo avvolto e un impl per ogni tratto per cui vuoi essere implementato\n" +"il tipo di involucro." + +#: src\patterns/behavioural/newtype.md:87 +#, fuzzy +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 "" +"I newtype sono molto comuni nel codice Rust. Le unità di astrazione o di " +"rappresentazione sono le\n" +"usi più comuni, ma possono essere utilizzati per altri motivi:" + +#: src\patterns/behavioural/newtype.md:90 +#, fuzzy +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 "" +"- limitare la funzionalità (ridurre le funzioni esposte o i tratti " +"implementati),\n" +"- fare in modo che un tipo con semantica di copia abbia semantica di " +"spostamento,\n" +"- astrazione fornendo un tipo più concreto e quindi nascondendo i tipi " +"interni,\n" +" per esempio.," + +#: src\patterns/behavioural/newtype.md:95 +msgid "" +"```rust,ignore\n" +"pub struct Foo(Bar);\n" +"```" +msgstr "" + +#: src\patterns/behavioural/newtype.md:99 +#, fuzzy +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 "" +"Qui, \"Bar\" potrebbe essere un tipo generico pubblico e \"T1\" e \"T2\" " +"sono interni\n" +"tipi. Gli utenti del nostro modulo non dovrebbero sapere che implementiamo " +"`Foo` utilizzando un `Bar`,\n" +"ma quello che in realtà stiamo nascondendo qui sono i tipi `T1` e `T2`, e " +"come vengono usati\n" +"con \"Barra\"." + +#: src\patterns/behavioural/newtype.md:106 +#, fuzzy +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 "" +"- [Tipi avanzati nel " +"libro](https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety " +"-e-astrazione)\n" +"- [Newtype in Haskell](https://wiki.haskell.org/Newtype)\n" +"- [Alias di " +"tipo](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), una cassa per " +"derivare molti\n" +" tratti incorporati su newtypes.\n" +"- [Il modello Newtype in " +"Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)" + +#: src\patterns/behavioural/RAII.md:1 +#, fuzzy +msgid "# RAII with guards" +msgstr "# RAII con le guardie" + +#: src\patterns/behavioural/RAII.md:5 +#, fuzzy +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 "" +"[RAII][wikipedia] sta per \"Resource Acquisition is Initialisation\" che è " +"a\n" +"nome terribile. L'essenza del modello è che l'inizializzazione della risorsa " +"è stata eseguita\n" +"nel costruttore di un oggetto e la finalizzazione nel distruttore. Questo " +"modello\n" +"è esteso in Rust utilizzando un oggetto RAII come protezione di alcune " +"risorse e facendo affidamento\n" +"sul sistema di tipo per garantire che l'accesso sia sempre mediato " +"dall'oggetto di guardia." + +#: src\patterns/behavioural/RAII.md:13 +#, fuzzy +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 "" +"Le guardie mutex sono il classico esempio di questo modello dalla libreria " +"std (this\n" +"è una versione semplificata dell'implementazione reale):" + +#: 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 +#, fuzzy +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 "" +"Laddove una risorsa deve essere finalizzata dopo l'uso, RAII può essere " +"utilizzata per farlo\n" +"finalizzazione. Se è un errore accedere a quella risorsa dopo la " +"finalizzazione, allora\n" +"questo modello può essere utilizzato per prevenire tali errori." + +#: src\patterns/behavioural/RAII.md:80 +#, fuzzy +msgid "" +"Prevents errors where a resource is not finalised and where a resource is " +"used\n" +"after finalisation." +msgstr "" +"Previene gli errori in cui una risorsa non è finalizzata e in cui viene " +"utilizzata una risorsa\n" +"dopo la finalizzazione." + +#: src\patterns/behavioural/RAII.md:85 +#, fuzzy +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 "" +"RAII è un modello utile per garantire che le risorse siano adeguatamente " +"deallocate o\n" +"finalizzato. Possiamo utilizzare il controllo del prestito in Rust per " +"prevenire staticamente\n" +"errori derivanti dall'utilizzo delle risorse dopo la finalizzazione." + +#: src\patterns/behavioural/RAII.md:89 +#, fuzzy +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 "" +"L'obiettivo principale del controllo del prestito è garantire che i " +"riferimenti ai dati non lo facciano\n" +"sopravvivere a quei dati. Il modello di guardia RAII funziona perché " +"l'oggetto di guardia\n" +"contiene un riferimento alla risorsa sottostante ed espone solo tale\n" +"Riferimenti. Rust assicura che la guardia non possa sopravvivere alla " +"risorsa sottostante\n" +"e che i riferimenti alla risorsa mediati dalla guardia non possono " +"sopravvivere\n" +"guardia. Per vedere come funziona è utile esaminare la firma di `deref`\n" +"senza elisione a vita:" + +#: 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 +#, fuzzy +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 "" +"Il riferimento restituito alla risorsa ha la stessa durata di `self` " +"(`'a`).\n" +"Il controllo del prestito assicura quindi che la durata del riferimento a " +"\"T\".\n" +"è più breve della durata di `self`." + +#: src\patterns/behavioural/RAII.md:107 +#, fuzzy +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 "" +"Si noti che l'implementazione di \"Deref\" non è una parte fondamentale di " +"questo modello, lo fa solo\n" +"utilizzando l'oggetto di protezione più ergonomico. Implementazione di un " +"metodo `get` in guardia\n" +"funziona altrettanto bene." + +#: src\patterns/behavioural/RAII.md:113 +#, fuzzy +msgid "[Finalisation in destructors idiom](../../idioms/dtor-finally.md)" +msgstr "" +"[Finalizzazione nell'idioma dei distruttori](../../idioms/dtor-finally.md)" + +#: src\patterns/behavioural/RAII.md:115 +#, fuzzy +msgid "" +"RAII is a common pattern in C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." +msgstr "" +"RAII è un modello comune in C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." + +#: src\patterns/behavioural/RAII.md:120 +#, fuzzy +msgid "" +"[Style guide " +"entry](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(currently just a placeholder)." +msgstr "" +"[Voce della guida di " +"stile](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(attualmente solo un segnaposto)." + +#: src\patterns/behavioural/strategy.md:1 +#, fuzzy +msgid "# Strategy (aka Policy)" +msgstr "# Strategia (ovvero Politica)" + +#: src\patterns/behavioural/strategy.md:5 +#, fuzzy +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 "" +"Il [modello di progettazione della " +"strategia](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"è una tecnica che consente la separazione delle preoccupazioni.\n" +"Consente inoltre di disaccoppiare i moduli software tramite [Dependency " +"Inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle)." + +#: src\patterns/behavioural/strategy.md:9 +#, fuzzy +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 "" +"L'idea di base alla base del modello di strategia è che, data la risoluzione " +"di un algoritmo\n" +"un problema particolare, definiamo solo lo scheletro dell'algoritmo in " +"astratto\n" +"livello e separiamo l'implementazione dell'algoritmo specifico in parti " +"diverse." + +#: src\patterns/behavioural/strategy.md:13 +#, fuzzy +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 "" +"In questo modo, un client che utilizza l'algoritmo può scegliere " +"un'implementazione specifica,\n" +"mentre il flusso di lavoro generale dell'algoritmo rimane lo stesso. In " +"altre parole, l'astratto\n" +"la specifica della classe non dipende dall'implementazione specifica del\n" +"classe derivata, ma l'implementazione specifica deve aderire alla specifica " +"astratta.\n" +"Questo è il motivo per cui lo chiamiamo \"Dependency Inversion\"." + +#: src\patterns/behavioural/strategy.md:21 +#, fuzzy +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 "" +"Immagina di lavorare a un progetto che genera report ogni mese.\n" +"Abbiamo bisogno che i report siano generati in diversi formati (strategie), " +"ad es.\n" +"nei formati `JSON` o `Plain Text`.\n" +"Ma le cose variano nel tempo e non sappiamo che tipo di requisiti potremmo " +"ottenere\n" +"in futuro. Ad esempio, potremmo aver bisogno di generare il nostro report in " +"un formato completamente nuovo\n" +"formato, o semplicemente modificare uno dei formati esistenti." + +#: src\patterns/behavioural/strategy.md:30 +#, fuzzy +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 "" +"In questo esempio le nostre invarianti (o astrazioni) sono `Context`, " +"`Formatter`,\n" +"e `Report`, mentre `Text` e `Json` sono le nostre strutture strategiche. " +"Queste strategie\n" +"devono implementare il tratto `Formatter`." + +#: 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 +#, fuzzy +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 "" +"Il vantaggio principale è la separazione delle preoccupazioni. Ad esempio, " +"in questo caso `Report`\n" +"non sa nulla di specifiche implementazioni di `Json` e `Text`,\n" +"considerando che le implementazioni di output non si preoccupano di come i " +"dati vengono preelaborati,\n" +"memorizzato e recuperato. L'unica cosa che devono sapere è il contesto e uno " +"specifico\n" +"tratto e metodo da implementare, ad esempio `Formatter` e `run`." + +#: src\patterns/behavioural/strategy.md:106 +#, fuzzy +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 "" +"Per ogni strategia deve essere implementato almeno un modulo, quindi numero " +"di moduli\n" +"aumenta con il numero di strategie. Se ci sono molte strategie tra cui " +"scegliere\n" +"quindi gli utenti devono sapere in che modo le strategie differiscono l'una " +"dall'altra." + +#: src\patterns/behavioural/strategy.md:112 +#, fuzzy +msgid "" +"In the previous example all strategies are implemented in a single file.\n" +"Ways of providing different strategies includes:" +msgstr "" +"Nell'esempio precedente tutte le strategie sono implementate in un singolo " +"file.\n" +"I modi per fornire diverse strategie includono:" + +#: src\patterns/behavioural/strategy.md:115 +#, fuzzy +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 "" +"- Tutto in un file (come mostrato in questo esempio, simile all'essere " +"separati come moduli)\n" +"- Separati come moduli, ad es. modulo `formatter::json`, modulo " +"`formatter::text`\n" +"- Usa i flag delle funzionalità del compilatore, ad es. Funzionalità " +"\"json\", funzionalità \"testo\".\n" +"- Separati come casse, ad es. cassa `json`, cassa `text`" + +#: src\patterns/behavioural/strategy.md:120 +#, fuzzy +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 "" +"Serde crate è un buon esempio del modello \"Strategia\" in azione. Serde " +"consente\n" +"[personalizzazione completa](https://serde.rs/custom-serialization.html) " +"della serializzazione\n" +"comportamento implementando manualmente i tratti `Serialize` e `Deserialize` " +"per il nostro\n" +"tipo. Ad esempio, potremmo facilmente scambiare `serde_json` con " +"`serde_cbor` poiché loro\n" +"esporre metodi simili. Avere questo rende l'helper crate `serde_transcode` " +"molto\n" +"più utile ed ergonomico." + +#: src\patterns/behavioural/strategy.md:127 +#, fuzzy +msgid "" +"However, we don't need to use traits in order to design this pattern in Rust." +msgstr "" +"Tuttavia, non abbiamo bisogno di utilizzare i tratti per progettare questo " +"modello in Rust." + +#: src\patterns/behavioural/strategy.md:129 +#, fuzzy +msgid "" +"The following toy example demonstrates the idea of the Strategy pattern " +"using Rust\n" +"`closures`:" +msgstr "" +"Il seguente esempio di giocattolo dimostra l'idea del pattern Strategy " +"usando Rust\n" +"`chiusure`:" + +#: 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 +#, fuzzy +msgid "In fact, Rust already uses this idea for `Options`'s `map` method:" +msgstr "Infatti, Rust usa già questa idea per il metodo `map` di `Options`:" + +#: 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 +#, fuzzy +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 "" +"- [Modello strategico](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"- [Iniezione di " +"dipendenza](https://en.wikipedia.org/wiki/Dependency_injection)\n" +"- [Progettazione basata su " +"criteri](https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design)" + +#: src\patterns/behavioural/visitor.md:1 +#, fuzzy +msgid "# Visitor" +msgstr "# Visitatore" + +#: src\patterns/behavioural/visitor.md:5 +#, fuzzy +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 "" +"Un visitatore incapsula un algoritmo che opera su un eterogeneo\n" +"collezione di oggetti. Consente di scrivere più algoritmi diversi\n" +"sugli stessi dati senza dover modificare i dati (o il loro file primario\n" +"comportamento)." + +#: src\patterns/behavioural/visitor.md:10 +#, fuzzy +msgid "" +"Furthermore, the visitor pattern allows separating the traversal of\n" +"a collection of objects from the operations performed on each object." +msgstr "" +"Inoltre, il modello del visitatore consente di separare l'attraversamento " +"di\n" +"una raccolta di oggetti dalle operazioni eseguite su ciascun oggetto." + +#: 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 +#, fuzzy +msgid "" +"One could implement further visitors, for example a type checker, without " +"having\n" +"to modify the AST data." +msgstr "" +"Si potrebbero implementare ulteriori visitatori, ad esempio un controllo di " +"tipo, senza avere\n" +"per modificare i dati AST." + +#: src\patterns/behavioural/visitor.md:74 +#, fuzzy +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 "" +"Il modello visitatore è utile ovunque tu voglia applicare un algoritmo\n" +"dati eterogenei. Se i dati sono omogenei, puoi utilizzare un modello simile " +"a un iteratore.\n" +"L'utilizzo di un oggetto visitatore (piuttosto che un approccio funzionale) " +"consente al visitatore di\n" +"essere stateful e quindi comunicare informazioni tra i nodi." + +#: src\patterns/behavioural/visitor.md:81 +#, fuzzy +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 "" +"È comune che i metodi `visit_*` restituiscano void (al contrario di quanto " +"accade nel\n" +"esempio). In tal caso è possibile scomporre il codice di attraversamento e " +"condividerlo\n" +"it tra algoritmi (e anche per fornire metodi predefiniti noop). In Ruggine, " +"il\n" +"un modo comune per farlo è fornire funzioni `walk_*` per ogni dato. Per\n" +"esempio," + +#: 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 +#, fuzzy +msgid "" +"In other languages (e.g., Java) it is common for data to have an `accept` " +"method\n" +"which performs the same duty." +msgstr "" +"In altri linguaggi (ad esempio, Java) è comune che i dati abbiano un metodo " +"`accept`\n" +"che svolge lo stesso compito." + +#: src\patterns/behavioural/visitor.md:108 +#, fuzzy +msgid "The visitor pattern is a common pattern in most OO languages." +msgstr "" +"Il modello del visitatore è un modello comune nella maggior parte delle " +"lingue OO." + +#: src\patterns/behavioural/visitor.md:110 +#, fuzzy +msgid "[Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern)" +msgstr "[Articolo di Wikipedia](https://en.wikipedia.org/wiki/Visitor_pattern)" + +#: src\patterns/behavioural/visitor.md:112 +#, fuzzy +msgid "" +"The [fold](../creational/fold.md) pattern is similar to visitor but " +"produces\n" +"a new version of the visited data structure." +msgstr "" +"Il modello [fold](../creational/fold.md) è simile al visitatore ma produce\n" +"una nuova versione della struttura dati visitata." + +#: src\patterns/creational/intro.md:1 +#, fuzzy +msgid "# Creational Patterns" +msgstr "# Modelli Creativi" + +#: src\patterns/creational/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" + +#: src\patterns/creational/intro.md:5 +#, fuzzy +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 "" +"> Design pattern che si occupano di meccanismi di creazione di oggetti, " +"cercando di creare oggetti\n" +"> in modo adeguato alla situazione. La forma base della creazione di oggetti " +"potrebbe\n" +"> comportare problemi di progettazione o una maggiore complessità del " +"progetto. Progettazione creazionale\n" +"> i modelli risolvono questo problema controllando in qualche modo la " +"creazione di questo oggetto." + +#: src\patterns/creational/builder.md:1 +#, fuzzy +msgid "# Builder" +msgstr "# Costruttore" + +#: src\patterns/creational/builder.md:5 +#, fuzzy +msgid "Construct an object with calls to a builder helper." +msgstr "Costruisci un oggetto con chiamate a un builder helper." + +#: 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 +#, fuzzy +msgid "" +"Useful when you would otherwise require many constructors or where\n" +"construction has side effects." +msgstr "" +"Utile quando altrimenti avresti bisogno di molti costruttori o dove\n" +"la costruzione ha effetti collaterali." + +#: src\patterns/creational/builder.md:70 +#, fuzzy +msgid "Separates methods for building from other methods." +msgstr "Separa i metodi per la compilazione da altri metodi." + +#: src\patterns/creational/builder.md:72 +#, fuzzy +msgid "Prevents proliferation of constructors." +msgstr "Previene la proliferazione di costruttori." + +#: src\patterns/creational/builder.md:74 +#, fuzzy +msgid "" +"Can be used for one-liner initialisation as well as more complex " +"construction." +msgstr "" +"Può essere utilizzato per l'inizializzazione one-liner e per costruzioni più " +"complesse." + +#: src\patterns/creational/builder.md:78 +#, fuzzy +msgid "" +"More complex than creating a struct object directly, or a simple " +"constructor\n" +"function." +msgstr "" +"Più complesso della creazione diretta di un oggetto struct o di un semplice " +"costruttore\n" +"funzione." + +#: src\patterns/creational/builder.md:83 +#, fuzzy +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 "" +"Questo modello è visto più frequentemente in Rust (e per oggetti più " +"semplici) che in\n" +"molte altre lingue perché Rust manca di sovraccarico. Dal momento che puoi " +"avere solo un file\n" +"singolo metodo con un determinato nome, avere più costruttori è meno " +"piacevole\n" +"Rust che in C++, Java o altri." + +#: src\patterns/creational/builder.md:88 +#, fuzzy +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 "" +"Questo modello viene spesso utilizzato quando l'oggetto builder è utile di " +"per sé,\n" +"piuttosto che essere solo un costruttore. Ad esempio, vedi\n" +"[`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html)\n" +"è un builder per " +"[`Child`](https://doc.rust-lang.org/std/process/struct.Child.html)\n" +"(un processo). In questi casi, il modello di denominazione \"T\" e " +"\"TBuilder\" non viene utilizzato." + +#: src\patterns/creational/builder.md:94 +#, fuzzy +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 "" +"L'esempio accetta e restituisce il builder per valore. Spesso è più " +"ergonomico\n" +"(e più efficiente) per prendere e restituire il builder come riferimento " +"mutabile. IL\n" +"prendere in prestito checker rende questo lavoro naturale. Questo approccio " +"ha il vantaggio che\n" +"si può scrivere codice come" + +#: 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 +#, fuzzy +msgid "as well as the `FooBuilder::new().a().b().build()` style." +msgstr "così come lo stile `FooBuilder::new().a().b().build()`." + +#: src\patterns/creational/builder.md:110 +#, fuzzy +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 "" +"- [Descrizione nella guida di " +"stile](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), una cassa per " +"automaticamente\n" +" implementare questo modello evitando il boilerplate.\n" +"- [Modello costruttore](../../idioms/ctor.md) per quando la costruzione è " +"più semplice.\n" +"- [Modello builder " +"(wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern)\n" +"- [Costruzione di valori " +"complessi](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder)" + +#: src\patterns/creational/fold.md:1 +#, fuzzy +msgid "# Fold" +msgstr "# Piega" + +#: src\patterns/creational/fold.md:5 +#, fuzzy +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 "" +"Esegui un algoritmo su ogni elemento in una raccolta di dati per creare un " +"nuovo elemento,\n" +"creando così una collezione completamente nuova." + +#: src\patterns/creational/fold.md:8 +#, fuzzy +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 "" +"L'etimologia qui non mi è chiara. Vengono utilizzati i termini \"piega\" e " +"\"cartella\".\n" +"nel compilatore Rust, anche se mi sembra più simile a una mappa che a\n" +"piegare nel senso comune. Vedere la discussione di seguito per maggiori " +"dettagli." + +#: 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 +#, fuzzy +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 "" +"Il risultato dell'esecuzione di `Renamer` su un AST è un nuovo AST identico " +"al vecchio\n" +"uno, ma con ogni nome cambiato in `foo`. Una cartella della vita reale " +"potrebbe averne alcuni\n" +"stato preservato tra i nodi nella struttura stessa." + +#: src\patterns/creational/fold.md:69 +#, fuzzy +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 "" +"È inoltre possibile definire una cartella per mappare una struttura di dati " +"a un'altra (but\n" +"di solito simile) struttura dei dati. Ad esempio, potremmo piegare un AST in " +"un HIR\n" +"albero (HIR sta per rappresentazione intermedia di alto livello)." + +#: src\patterns/creational/fold.md:75 +#, fuzzy +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 "" +"È comune voler mappare una struttura dati eseguendo alcune operazioni su\n" +"ciascun nodo della struttura. Per operazioni semplici su strutture dati " +"semplici,\n" +"questo può essere fatto usando `Iterator::map`. Per operazioni più " +"complesse, forse\n" +"dove i nodi precedenti possono influenzare l'operazione sui nodi successivi " +"o dove l'iterazione\n" +"sopra la struttura dei dati non è banale, l'utilizzo del modello di " +"piegatura lo è di più\n" +"adeguata." + +#: src\patterns/creational/fold.md:82 +#, fuzzy +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 "" +"Come il modello del visitatore, il modello di piegatura ci consente di " +"separare l'attraversamento di a\n" +"struttura dati dalle operazioni eseguite su ciascun nodo." + +#: src\patterns/creational/fold.md:87 +#, fuzzy +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 "" +"La mappatura delle strutture dati in questo modo è comune nei linguaggi " +"funzionali. Nell'OO\n" +"lingue, sarebbe più comune mutare la struttura dei dati sul posto. IL\n" +"L'approccio \"funzionale\" è comune in Rust, principalmente a causa della " +"preferenza per\n" +"immutabilità. L'utilizzo di nuove strutture di dati, piuttosto che la " +"mutazione di quelle vecchie, rende\n" +"ragionamento sul codice più facile nella maggior parte dei casi." + +#: src\patterns/creational/fold.md:93 +#, fuzzy +msgid "" +"The trade-off between efficiency and reusability can be tweaked by changing " +"how\n" +"nodes are accepted by the `fold_*` methods." +msgstr "" +"Il compromesso tra efficienza e riusabilità può essere modificato " +"modificando il modo\n" +"i nodi sono accettati dai metodi `fold_*`." + +#: src\patterns/creational/fold.md:96 +#, fuzzy +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 "" +"Nell'esempio sopra operiamo sui puntatori `Box`. Dal momento che questi " +"possiedono i loro dati\n" +"esclusivamente, la copia originale della struttura dati non può essere " +"riutilizzata. Sul\n" +"d'altra parte se un nodo non viene modificato, riutilizzarlo è molto " +"efficiente." + +#: 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 +#, fuzzy +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 "" +"L'uso di un puntatore contato di riferimento offre il meglio di entrambi i " +"mondi: possiamo riutilizzarlo\n" +"la struttura dati originale e non è necessario clonare nodi non modificati. " +"Tuttavia,\n" +"sono meno ergonomici da usare e significano che le strutture dati non " +"possono esserlo\n" +"mutevole." + +#: src\patterns/creational/fold.md:111 +#, fuzzy +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 "" +"Gli iteratori hanno un metodo `fold`, tuttavia questo ripiega una struttura " +"di dati in a\n" +"valore, piuttosto che in una nuova struttura di dati. La \"mappa\" di un " +"iteratore è più simile\n" +"questo schema di piegatura." + +#: src\patterns/creational/fold.md:115 +#, fuzzy +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 "" +"In altre lingue, fold è solitamente usato nel senso degli iteratori di " +"Rust,\n" +"piuttosto che questo modello. Alcuni linguaggi funzionali hanno potenti " +"costrutti per\n" +"eseguire mappe flessibili su strutture dati." + +#: src\patterns/creational/fold.md:119 +#, fuzzy +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 "" +"Il pattern [visitor](../behavioural/visitor.md) è strettamente correlato a " +"fold.\n" +"Condividono il concetto di percorrere una struttura dati su cui eseguire " +"un'operazione\n" +"ciascun nodo. Tuttavia, il visitatore non crea una nuova struttura di dati " +"né consuma\n" +"quello vecchio." + +#: src\patterns/structural/intro.md:1 +#, fuzzy +msgid "# Structural Patterns" +msgstr "# Modelli strutturali" + +#: src\patterns/structural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +msgstr "Da [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" + +#: src\patterns/structural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that ease the design by identifying a simple way to " +"realize relationships\n" +"> among entities." +msgstr "" +"> Design pattern che facilitano la progettazione individuando un modo " +"semplice per realizzare relazioni\n" +"> tra enti." + +#: src\patterns/structural/compose-structs.md:1 +#, fuzzy +msgid "# Compose structs together for better borrowing" +msgstr "# Comporre le strutture insieme per un migliore prestito" + +#: src\patterns/structural/compose-structs.md:3 +#, fuzzy +msgid "TODO - this is not a very snappy name" +msgstr "TODO - questo non è un nome molto accattivante" + +#: src\patterns/structural/compose-structs.md:7 +#, fuzzy +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 "" +"A volte una struttura di grandi dimensioni causerà problemi con il controllo " +"del prestito, anche se\n" +"i campi possono essere presi in prestito indipendentemente, a volte l'intera " +"struttura finisce per esserlo\n" +"utilizzato in una sola volta, impedendo altri usi. Una soluzione potrebbe " +"essere quella di scomporre la struct\n" +"in diverse strutture più piccole. Quindi componili insieme nell'originale\n" +"struct. Quindi ogni struttura può essere presa in prestito separatamente e " +"avere una maggiore flessibilità\n" +"comportamento." + +#: src\patterns/structural/compose-structs.md:14 +#, fuzzy +msgid "" +"This will often lead to a better design in other ways: applying this design\n" +"pattern often reveals smaller units of functionality." +msgstr "" +"Questo spesso porterà a un design migliore in altri modi: applicando questo " +"design\n" +"pattern rivela spesso unità di funzionalità più piccole." + +#: src\patterns/structural/compose-structs.md:19 +#, fuzzy +msgid "" +"Here is a contrived example of where the borrow checker foils us in our plan " +"to\n" +"use a struct:" +msgstr "" +"Ecco un esempio artificioso di dove il controllore del prestito ci sventa " +"nel nostro piano\n" +"usa una struttura:" + +#: 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 +#, fuzzy +msgid "" +"We can apply this design pattern and refactor `A` into two smaller structs, " +"thus\n" +"solving the borrow checking issue:" +msgstr "" +"Possiamo quindi applicare questo modello di progettazione e rifattorizzare " +"\"A\" in due strutture più piccole\n" +"risolvere il problema del controllo del prestito:" + +#: 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 +#, fuzzy +msgid "TODO Why and where you should use the pattern" +msgstr "TODO Perché e dove dovresti usare il modello" + +#: src\patterns/structural/compose-structs.md:77 +#, fuzzy +msgid "Lets you work around limitations in the borrow checker." +msgstr "Consente di aggirare le limitazioni nel controllo del prestito." + +#: src\patterns/structural/compose-structs.md:79 +#, fuzzy +msgid "Often produces a better design." +msgstr "Spesso produce un design migliore." + +#: src\patterns/structural/compose-structs.md:83 +#, fuzzy +msgid "Leads to more verbose code." +msgstr "Porta a un codice più dettagliato." + +#: src\patterns/structural/compose-structs.md:85 +#, fuzzy +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 "" +"A volte, le strutture più piccole non sono buone astrazioni, e quindi ci " +"ritroviamo\n" +"un design peggiore. Questo è probabilmente un \"odore di codice\", che " +"indica che il programma\n" +"dovrebbe essere rifattorizzato in qualche modo." + +#: src\patterns/structural/compose-structs.md:91 +#, fuzzy +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 "" +"Questo modello non è richiesto nelle lingue che non hanno un controllo del " +"prestito, quindi\n" +"in questo senso è unico per Rust. Tuttavia, creando unità di funzionalità " +"più piccole\n" +"spesso porta a un codice più pulito: un principio del software ampiamente " +"riconosciuto\n" +"ingegneria, indipendente dalla lingua." + +#: src\patterns/structural/compose-structs.md:96 +#, fuzzy +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 "" +"Questo modello si basa sul controllo del prestito di Rust per poter prendere " +"in prestito i campi\n" +"indipendentemente l'uno dall'altro. Nell'esempio, il controllo del prestito " +"sa che `a.b`\n" +"e \"a.c\" sono distinti e possono essere presi in prestito " +"indipendentemente, non cerca di farlo\n" +"prendi in prestito tutta la `a`, il che renderebbe questo modello inutile." + +#: src\patterns/structural/small-crates.md:1 +#, fuzzy +msgid "# Prefer small crates" +msgstr "# Preferisci casse piccole" + +#: src\patterns/structural/small-crates.md:5 +#, fuzzy +msgid "Prefer small crates that do one thing well." +msgstr "Preferisci piccole casse che fanno bene una cosa." + +#: src\patterns/structural/small-crates.md:7 +#, fuzzy +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 "" +"Cargo e crates.io semplificano l'aggiunta di librerie di terze parti, molto " +"più di\n" +"diciamo in C o C++. Inoltre, poiché i pacchetti su crates.io non possono " +"essere modificati o rimossi\n" +"dopo la pubblicazione, qualsiasi build che funziona ora dovrebbe continuare " +"a funzionare in futuro.\n" +"Dovremmo trarre vantaggio da questi strumenti e utilizzare dipendenze più " +"piccole e più granulari." + +#: src\patterns/structural/small-crates.md:14 +#, fuzzy +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 "" +"- Le casse piccole sono più facili da capire e incoraggiano un codice più " +"modulare.\n" +"- Le casse consentono di riutilizzare il codice tra i progetti.\n" +" Ad esempio, la cassa `url` è stata sviluppata come parte del motore del " +"browser Servo,\n" +" ma da allora ha trovato ampio utilizzo al di fuori del progetto.\n" +"- Dal momento che l'unità di compilazione\n" +" of Rust è la cassa, la suddivisione di un progetto in più casse può " +"consentirne di più\n" +" il codice da costruire in parallelo." + +#: src\patterns/structural/small-crates.md:24 +#, fuzzy +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 "" +"- Questo può portare a \"l'inferno della dipendenza\", quando un progetto " +"dipende da più conflitti\n" +" versioni di una cassa allo stesso tempo. Ad esempio, la cassa `url` ha " +"entrambe le versioni\n" +" 1.0 e 0.5. Poiché \"Url\" da \"url:1.0\" e \"Url\" da \"url:0.5\" sono\n" +" tipi diversi, un client HTTP che utilizza `url:0.5` non accetterebbe i " +"valori `Url`\n" +" da un web scraper che utilizza `url:1.0`.\n" +"- I pacchetti su crates.io non sono curati. Una cassa può essere scritta " +"male, avere\n" +" documentazione inutile o essere apertamente malizioso.\n" +"- Due piccole casse possono essere meno ottimizzate di una grande, poiché il " +"compilatore\n" +" non esegue l'ottimizzazione del tempo di collegamento (LTO) per " +"impostazione predefinita." + +#: src\patterns/structural/small-crates.md:36 +#, fuzzy +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions\n" +"for converting `&T` to `&[T]`." +msgstr "" +"Il crate [`ref_slice`](https://crates.io/crates/ref_slice) fornisce " +"funzioni\n" +"per convertire \"&T\" in \"&[T]\"." + +#: src\patterns/structural/small-crates.md:39 +#, fuzzy +msgid "" +"The [`url`](https://crates.io/crates/url) crate provides tools for working " +"with\n" +"URLs." +msgstr "" +"Il crate [`url`](https://crates.io/crates/url) fornisce gli strumenti per " +"lavorare con\n" +"URL." + +#: src\patterns/structural/small-crates.md:42 +#, fuzzy +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 "" +"Il crate [`num_cpus`](https://crates.io/crates/num_cpus) fornisce una " +"funzione per\n" +"interrogare il numero di CPU su una macchina." + +#: src\patterns/structural/small-crates.md:47 +#, fuzzy +msgid "- [crates.io: The Rust community crate host](https://crates.io/)" +msgstr "- [crates.io: host di casse della community di Rust](https://crates.io/)" + +#: src\patterns/structural/unsafe-mods.md:1 +#, fuzzy +msgid "# Contain unsafety in small modules" +msgstr "# Contenere la sicurezza in piccoli moduli" + +#: src\patterns/structural/unsafe-mods.md:5 +#, fuzzy +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 "" +"Se hai un codice \"non sicuro\", crea il modulo più piccolo possibile che " +"possa sostenere\n" +"gli invarianti necessari per costruire un'interfaccia sicura minima " +"sull'insicurezza. Incorporare\n" +"questo in un modulo più grande che contiene solo codice sicuro e presenta " +"un'ergonomia\n" +"interfaccia. Si noti che il modulo esterno può contenere funzioni e metodi " +"non sicuri\n" +"che chiamano direttamente nel codice non sicuro. Gli utenti possono " +"utilizzarlo per ottenere vantaggi in termini di velocità." + +#: src\patterns/structural/unsafe-mods.md:13 +#, fuzzy +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 "" +"- Questo limita il codice non sicuro che deve essere controllato\n" +"- Scrivere il modulo esterno è molto più semplice, dato che puoi contare " +"sulle garanzie\n" +" del modulo interno" + +#: src\patterns/structural/unsafe-mods.md:19 +#, fuzzy +msgid "" +"- Sometimes, it may be hard to find a suitable interface.\n" +"- The abstraction may introduce inefficiencies." +msgstr "" +"- A volte può essere difficile trovare un'interfaccia adatta.\n" +"- L'astrazione può introdurre inefficienze." + +#: src\patterns/structural/unsafe-mods.md:24 +#, fuzzy +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 "" +"- Il crate [`toolshed`](https://docs.rs/toolshed) contiene le sue operazioni " +"non sicure\n" +" nei sottomoduli, presentando un'interfaccia sicura per gli utenti.\n" +"- La classe `String` di `std` è un wrapper su `Vec` con l'aggiunta " +"dell'invariante\n" +" che i contenuti devono essere UTF-8 validi. Le operazioni su \"Stringa\" " +"assicurano questo\n" +" comportamento.\n" +" Tuttavia, gli utenti hanno la possibilità di utilizzare un metodo \"non " +"sicuro\" per creare una \"Stringa\",\n" +" in tal caso spetta a loro l'onere di garantire la validità dei contenuti." + +#: src\patterns/structural/unsafe-mods.md:34 +#, fuzzy +msgid "" +"- [Ralf Jung's Blog about invariants in unsafe " +"code](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" +msgstr "" +"- [Blog di Ralf Jung sulle invarianti nel codice non " +"sicuro](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" + +#: src\patterns/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Patterns" +msgstr "# Modelli FFI" + +#: src\patterns/ffi/intro.md:3 +#, fuzzy +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 "" +"Scrivere il codice FFI è un intero corso in sé.\n" +"Tuttavia, ci sono diversi idiomi qui che possono fungere da puntatori ed " +"evitare trappole\n" +"per utenti inesperti di Rust non sicuro." + +#: src\patterns/ffi/intro.md:7 +#, fuzzy +msgid "This section contains design patterns that may be useful when doing FFI." +msgstr "" +"Questa sezione contiene modelli di progettazione che possono essere utili " +"durante l'esecuzione di FFI." + +#: src\patterns/ffi/intro.md:9 +#, fuzzy +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 "" +"1. [API basata su oggetti](./export.md) design con buone caratteristiche di " +"sicurezza della memoria,\n" +" e un confine netto di ciò che è sicuro e ciò che non lo è\n" +"\n" +"2. [Type Consolidation into Wrappers](./wrappers.md) - raggruppa più tipi di " +"Rust\n" +" insieme in un \"oggetto\" opaco" + +#: src\patterns/ffi/export.md:1 +#, fuzzy +msgid "# Object-Based APIs" +msgstr "# API basate su oggetti" + +#: src\patterns/ffi/export.md:5 +#, fuzzy +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 "" +"Quando si progettano API in Rust che sono esposte ad altri linguaggi, ce ne " +"sono alcune\n" +"importanti principi di progettazione che sono contrari al normale design " +"dell'API di Rust:" + +#: src\patterns/ffi/export.md:8 +#, fuzzy +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 "" +"1. Tutti i tipi Encapsulated dovrebbero essere _posseduti_ da Rust, " +"_gestiti_ dall'utente,\n" +" e _opaco_.\n" +"2. Tutti i tipi di dati transazionali devono essere _di proprietà_ " +"dell'utente e _trasparenti_.\n" +"3. Tutti i comportamenti delle librerie dovrebbero essere funzioni che " +"agiscono sui tipi incapsulati.\n" +"4. Tutto il comportamento della libreria dovrebbe essere incapsulato in tipi " +"non basati sulla struttura,\n" +" ma _provenienza/vita_." + +#: src\patterns/ffi/export.md:17 +#, fuzzy +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 "" +"Rust ha il supporto FFI integrato per altre lingue.\n" +"Lo fa fornendo agli autori di crate un modo per fornire API compatibili con " +"C\n" +"attraverso diversi ABI (sebbene ciò non sia importante per questa pratica)." + +#: src\patterns/ffi/export.md:21 +#, fuzzy +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 "" +"Rust FFI ben progettato segue i principi di progettazione dell'API C, " +"compromettendo al contempo il\n" +"progettare in Rust il meno possibile. Ci sono tre obiettivi con qualsiasi " +"API esterna:" + +#: src\patterns/ffi/export.md:24 +#, fuzzy +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 "" +"1. Rendilo facile da usare nella lingua di destinazione.\n" +"2. Evita il più possibile che l'API determini l'insicurezza interna sul lato " +"Rust.\n" +"3. Mantenere basso il potenziale di insicurezza della memoria e di " +"\"comportamento indefinito\" di Rust\n" +" possibile." + +#: src\patterns/ffi/export.md:29 +#, fuzzy +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 "" +"Il codice Rust deve fidarsi della sicurezza della memoria della lingua " +"straniera oltre un certo\n" +"punto. Tuttavia, ogni bit di codice \"non sicuro\" sul lato Rust è " +"un'opportunità per\n" +"bug o per esacerbare il `comportamento indefinito`." + +#: src\patterns/ffi/export.md:33 +#, fuzzy +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 "" +"Ad esempio, se la provenienza di un puntatore è errata, potrebbe trattarsi " +"di un segfault dovuto a\n" +"accesso alla memoria non valido. Ma se viene manipolato da codice non " +"sicuro, potrebbe diventarlo\n" +"corruzione completa dell'heap." + +#: src\patterns/ffi/export.md:37 +#, fuzzy +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 "" +"La progettazione dell'API basata su oggetti consente di scrivere shim con " +"una buona sicurezza della memoria\n" +"caratteristiche e un confine netto tra ciò che è sicuro e ciò che è \"non " +"sicuro\"." + +#: src\patterns/ffi/export.md:42 +#, fuzzy +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 "" +"Lo standard POSIX definisce l'API per accedere a un database su file, noto " +"come " +"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h) " +".\n" +"È un eccellente esempio di API \"basata su oggetti\"." + +#: src\patterns/ffi/export.md:45 +#, fuzzy +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 "" +"Ecco la definizione in C, che si spera dovrebbe essere facile da leggere per " +"quelli\n" +"coinvolti in FFI. Il commento qui sotto dovrebbe aiutare a spiegarlo per " +"coloro che\n" +"perdere le sottigliezze." + +#: 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 +#, fuzzy +msgid "This API defines two types: `DBM` and `datum`." +msgstr "Questa API definisce due tipi: `DBM` e `datum`." + +#: src\patterns/ffi/export.md:66 +#, fuzzy +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 "" +"Il tipo `DBM` è stato chiamato un tipo \"incapsulato\" sopra.\n" +"È progettato per contenere lo stato interno e funge da punto di ingresso per " +"il\n" +"comportamento della biblioteca" + +#: src\patterns/ffi/export.md:70 +#, fuzzy +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 "" +"È completamente opaco per l'utente, che da allora non può creare un " +"\"DBM\".\n" +"non ne conoscono le dimensioni o il layout. Invece, devono chiamare " +"\"dbm_open\" e così via\n" +"dà loro solo _un puntatore a uno_." + +#: src\patterns/ffi/export.md:74 +#, fuzzy +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 "" +"Ciò significa che tutti i `DBM` sono \"di proprietà\" della libreria in un " +"certo senso Rust.\n" +"Lo stato interno di dimensioni sconosciute viene mantenuto in memoria " +"controllato dalla libreria,\n" +"non l'utente. L'utente può gestire il suo ciclo di vita solo con `apri` e " +"`chiudi`,\n" +"ed eseguire operazioni su di esso con le altre funzioni." + +#: src\patterns/ffi/export.md:79 +#, fuzzy +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 "" +"Il tipo `datum` era soprannominato tipo \"transazionale\".\n" +"È progettato per facilitare lo scambio di informazioni tra la biblioteca e\n" +"suo utente." + +#: src\patterns/ffi/export.md:83 +#, fuzzy +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 "" +"Il database è progettato per memorizzare \"dati non strutturati\", senza una " +"lunghezza predefinita\n" +"o significato. Di conseguenza, il \"dato\" è l'equivalente in C di una fetta " +"di ruggine: un mucchio\n" +"di byte e un conteggio di quanti ce ne sono. La differenza principale è che " +"c'è\n" +"nessuna informazione sul tipo, che è ciò che indica \"void\"." + +#: src\patterns/ffi/export.md:88 +#, fuzzy +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 "" +"Tieni presente che questa intestazione è scritta dal punto di vista della " +"biblioteca.\n" +"L'utente probabilmente ha un tipo che sta usando, che ha una dimensione " +"nota.\n" +"Ma alla libreria non interessa, e secondo le regole del casting C, qualsiasi " +"tipo dietro a\n" +"il puntatore può essere lanciato su \"void\"." + +#: src\patterns/ffi/export.md:93 +#, fuzzy +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 "" +"Come notato in precedenza, questo tipo è _trasparente_ per l'utente. Ma " +"anche questo tipo lo è\n" +"_posseduto_ dall'utente.\n" +"Questo ha sottili ramificazioni, a causa di quel puntatore al suo interno.\n" +"La domanda è: chi possiede la memoria a cui punta il puntatore?" + +#: src\patterns/ffi/export.md:98 +#, fuzzy +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 "" +"La risposta per la migliore sicurezza della memoria è \"l'utente\".\n" +"Ma in casi come il recupero di un valore, l'utente non sa come allocare\n" +"correttamente (poiché non sanno quanto è lungo il valore). In questo caso, " +"la biblioteca\n" +"il codice dovrebbe utilizzare l'heap a cui l'utente ha accesso, come la " +"libreria C\n" +"`malloc` e `free` -- e poi _trasferire la proprietà_ nel senso di Rust." + +#: src\patterns/ffi/export.md:104 +#, fuzzy +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 "" +"Tutto questo può sembrare speculativo, ma questo è ciò che significa un " +"puntatore in C.\n" +"Significa la stessa cosa di Rust: \"durata definita dall'utente\".\n" +"L'utente della libreria deve leggere la documentazione per poterla " +"utilizzare correttamente.\n" +"Detto questo, ci sono alcune decisioni che hanno conseguenze minori o " +"maggiori se gli utenti\n" +"fallo male. Ridurli al minimo è ciò di cui tratta questa best practice e la " +"chiave\n" +"è _trasferire la proprietà di tutto ciò che è trasparente_." + +#: src\patterns/ffi/export.md:113 +#, fuzzy +msgid "" +"This minimizes the number of memory safety guarantees the user must uphold " +"to a\n" +"relatively small number:" +msgstr "" +"Ciò riduce al minimo il numero di garanzie di sicurezza della memoria che " +"l'utente deve mantenere a\n" +"numero relativamente piccolo:" + +#: src\patterns/ffi/export.md:116 +#, fuzzy +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 "" +"1. Non chiamare alcuna funzione con un puntatore non restituito da " +"`dbm_open` (invalid\n" +" accesso o corruzione).\n" +"2. Non chiamare alcuna funzione su un puntatore dopo la chiusura (usa dopo " +"free).\n" +"3. Il `dptr` su qualsiasi `dato` deve essere `NULL` o puntare a una fetta di " +"memoria valida\n" +" alla lunghezza pubblicizzata." + +#: src\patterns/ffi/export.md:122 +#, fuzzy +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 "" +"Inoltre, evita molti problemi di provenienza del puntatore.\n" +"Per capire perché, consideriamo un'alternativa in modo approfondito: " +"l'iterazione chiave." + +#: src\patterns/ffi/export.md:125 +#, fuzzy +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 "" +"Rust è ben noto per i suoi iteratori.\n" +"Quando ne implementa uno, il programmatore crea un tipo separato con una " +"durata limitata\n" +"al suo proprietario e implementa il tratto `Iterator`." + +#: src\patterns/ffi/export.md:129 +#, fuzzy +msgid "Here is how iteration would be done in Rust for `DBM`:" +msgstr "Ecco come verrebbe eseguita l'iterazione in Rust per `DBM`:" + +#: 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 +#, fuzzy +msgid "" +"This is clean, idiomatic, and safe. thanks to Rust's guarantees.\n" +"However, consider what a straightforward API translation would look like:" +msgstr "" +"Questo è pulito, idiomatico e sicuro. grazie alle garanzie di Rust.\n" +"Tuttavia, considera come sarebbe una semplice traduzione API:" + +#: 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 +#, fuzzy +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 "" +"Questa API perde un'informazione chiave: la durata dell'iteratore no\n" +"superare la durata dell'oggetto `Dbm` che lo possiede. Un utente della " +"biblioteca potrebbe\n" +"usalo in un modo che fa sì che l'iteratore sopravviva ai dati su cui sta " +"iterando,\n" +"con conseguente lettura della memoria non inizializzata." + +#: src\patterns/ffi/export.md:173 +#, fuzzy +msgid "" +"This example written in C contains a bug that will be explained afterwards:" +msgstr "" +"Questo esempio scritto in C contiene un bug che verrà spiegato in seguito:" + +#: 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 +#, fuzzy +msgid "" +"This bug is a classic. Here's what happens when the iterator returns the\n" +"end-of-iteration marker:" +msgstr "" +"Questo bug è un classico. Ecco cosa succede quando l'iteratore restituisce " +"il\n" +"marcatore di fine iterazione:" + +#: src\patterns/ffi/export.md:205 +#, fuzzy +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 "" +"1. La condizione del ciclo imposta \"l\" su zero ed entra nel ciclo perché " +"\"0 >= 0\".\n" +"2. La lunghezza viene incrementata, in questo caso di zero.\n" +"3. L'istruzione if è vera, quindi il database è chiuso. Dovrebbe esserci una " +"pausa\n" +" dichiarazione qui.\n" +"4. La condizione del ciclo viene eseguita di nuovo, causando una chiamata " +"`next` sull'oggetto chiuso." + +#: src\patterns/ffi/export.md:211 +#, fuzzy +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 "" +"La parte peggiore di questo bug?\n" +"Se l'implementazione di Rust è stata attenta, questo codice funzionerà per " +"la maggior parte del tempo!\n" +"Se la memoria per l'oggetto `Dbm` non viene riutilizzata immediatamente, un " +"controllo interno\n" +"quasi sicuramente fallirà, con il risultato che l'iteratore restituirà un " +"`-1` che indica\n" +"un errore. Ma occasionalmente, causerà un errore di segmentazione o, peggio " +"ancora,\n" +"corruzione della memoria senza senso!" + +#: src\patterns/ffi/export.md:218 +#, fuzzy +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 "" +"Niente di tutto questo può essere evitato da Rust.\n" +"Dal suo punto di vista, ha messo quegli oggetti nel suo heap, ha restituito " +"loro dei puntatori,\n" +"e ha rinunciato al controllo delle loro vite. Il codice C deve semplicemente " +"\"giocare bene\"." + +#: src\patterns/ffi/export.md:222 +#, fuzzy +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 "" +"Il programmatore deve leggere e comprendere la documentazione dell'API.\n" +"Sebbene alcuni considerino la norma per il corso in C, una buona " +"progettazione dell'API può mitigare\n" +"questo rischio. L'API POSIX per `DBM` ha fatto questo _consolidando la " +"proprietà_ di\n" +"l'iteratore con il suo genitore:" + +#: 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 +#, fuzzy +msgid "" +"Thus, all the lifetimes were bound together, and such unsafety was prevented." +msgstr "" +"Così, tutte le vite sono state legate insieme e tale insicurezza è stata " +"prevenuta." + +#: src\patterns/ffi/export.md:236 +#, fuzzy +msgid "" +"However, this design choice also has a number of drawbacks, which should be\n" +"considered as well." +msgstr "" +"Tuttavia, questa scelta progettuale presenta anche una serie di " +"inconvenienti, che dovrebbero essere\n" +"considerato pure." + +#: src\patterns/ffi/export.md:239 +#, fuzzy +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 "" +"Innanzitutto, l'API stessa diventa meno espressiva.\n" +"Con POSIX DBM, esiste un solo iteratore per oggetto e ogni chiamata cambia\n" +"il suo stato. Questo è molto più restrittivo degli iteratori in quasi tutte " +"le lingue,\n" +"anche se è sicuro. Forse con altri oggetti correlati, le cui vite sono\n" +"meno gerarchica, questa limitazione è più un costo che la sicurezza." + +#: src\patterns/ffi/export.md:245 +#, fuzzy +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 "" +"In secondo luogo, a seconda delle relazioni tra le parti dell'API, uno " +"sforzo di progettazione significativo\n" +"può essere coinvolto. Molti dei punti di progettazione più semplici hanno " +"altri modelli associati\n" +"con loro:" + +#: src\patterns/ffi/export.md:249 +#, fuzzy +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 "" +"- [Consolidamento del tipo di wrapper](./wrappers.md) raggruppa più tipi di " +"ruggine insieme\n" +" in un \"oggetto\" opaco\n" +"\n" +"- [FFI Error Passing](../../idioms/ffi/errors.md) spiega la gestione degli " +"errori con numeri interi\n" +" codici e valori di ritorno sentinella (come i puntatori `NULL`)\n" +"\n" +"- [Accettare stringhe esterne](../../idioms/ffi/accepting-strings.md) " +"consente di accettare\n" +" stringhe con codice non sicuro minimo ed è più facile da ottenere rispetto " +"a\n" +" [Passaggio di stringhe a FFI](../../idioms/ffi/passing-strings.md)" + +#: src\patterns/ffi/export.md:259 +#, fuzzy +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 "" +"Tuttavia, non tutte le API possono essere eseguite in questo modo.\n" +"Spetta al miglior giudizio del programmatore stabilire chi sia il suo " +"pubblico." + +#: src\patterns/ffi/wrappers.md:1 +#, fuzzy +msgid "# Type Consolidation into Wrappers" +msgstr "# Digitare Consolidation into Wrapper" + +#: src\patterns/ffi/wrappers.md:5 +#, fuzzy +msgid "" +"This pattern is designed to allow gracefully handling multiple related " +"types,\n" +"while minimizing the surface area for memory unsafety." +msgstr "" +"Questo modello è progettato per consentire di gestire con garbo più tipi " +"correlati,\n" +"riducendo al minimo la superficie per l'insicurezza della memoria." + +#: src\patterns/ffi/wrappers.md:8 +#, fuzzy +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 "" +"Uno dei capisaldi delle regole di aliasing di Rust sono le vite.\n" +"Ciò garantisce che molti modelli di accesso tra i tipi possano essere sicuri " +"per la memoria,\n" +"sicurezza della gara di dati inclusa." + +#: src\patterns/ffi/wrappers.md:12 +#, fuzzy +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 "" +"Tuttavia, quando i tipi di Rust vengono esportati in altri linguaggi, di " +"solito vengono trasformati\n" +"in puntatori. In Rust, un puntatore significa \"l'utente gestisce la vita " +"del puntatore\".\n" +"È loro responsabilità evitare l'insicurezza della memoria." + +#: src\patterns/ffi/wrappers.md:16 +#, fuzzy +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 "" +"È quindi richiesto un certo livello di fiducia nel codice utente, in " +"particolare per quanto riguarda l'uso dopo il libero\n" +"per cui Rust non può fare nulla. Tuttavia, alcuni progetti di API comportano " +"oneri maggiori\n" +"di altri sul codice scritto nell'altra lingua." + +#: src\patterns/ffi/wrappers.md:20 +#, fuzzy +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 "" +"L'API a rischio più basso è il \"wrapper consolidato\", in cui tutte le " +"possibili interazioni\n" +"con un oggetto vengono piegati in un \"tipo wrapper\", mantenendo pulita " +"l'API di Rust." + +#: src\patterns/ffi/wrappers.md:25 +#, fuzzy +msgid "" +"To understand this, let us look at a classic example of an API to export: " +"iteration\n" +"through a collection." +msgstr "" +"Per capirlo, esaminiamo un classico esempio di API da esportare: " +"l'iterazione\n" +"attraverso una raccolta" + +#: src\patterns/ffi/wrappers.md:28 +#, fuzzy +msgid "That API looks like this:" +msgstr "L'API ha questo aspetto:" + +#: src\patterns/ffi/wrappers.md:30 +#, fuzzy +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 "" +"1. L'iteratore viene inizializzato con `first_key`.\n" +"2. Ogni chiamata a `next_key` farà avanzare l'iteratore.\n" +"3. Le chiamate a `next_key` se l'iteratore è alla fine non faranno nulla.\n" +"4. Come notato sopra, l'iteratore è \"inserito\" nella raccolta (a " +"differenza del file native\n" +" API ruggine)." + +#: src\patterns/ffi/wrappers.md:36 +#, fuzzy +msgid "" +"If the iterator implements `nth()` efficiently, then it is possible to make " +"it\n" +"ephemeral to each function call:" +msgstr "" +"Se l'iteratore implementa `nth()` in modo efficiente, allora è possibile " +"farlo\n" +"effimero per ogni chiamata di funzione:" + +#: 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 +#, fuzzy +msgid "As a result, the wrapper is simple and contains no `unsafe` code." +msgstr "" +"Di conseguenza, il wrapper è semplice e non contiene codice \"non sicuro\"." + +#: src\patterns/ffi/wrappers.md:65 +#, fuzzy +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 "" +"Questo rende le API più sicure da usare, evitando problemi con la durata tra " +"i tipi.\n" +"Vedere [API basate su oggetti](./export.md) per ulteriori informazioni sui " +"vantaggi e le insidie\n" +"questo evita." + +#: src\patterns/ffi/wrappers.md:71 +#, fuzzy +msgid "" +"Often, wrapping types is quite difficult, and sometimes a Rust API " +"compromise\n" +"would make things easier." +msgstr "" +"Spesso, il wrapping dei tipi è piuttosto difficile e talvolta un compromesso " +"con l'API Rust\n" +"renderebbe le cose più facili." + +#: src\patterns/ffi/wrappers.md:74 +#, fuzzy +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 "" +"Ad esempio, considera un iteratore che non implementa in modo efficiente " +"`nth()`.\n" +"Varrebbe sicuramente la pena inserire una logica speciale per far gestire " +"l'oggetto\n" +"iterazione interna o per supportare un diverso modello di accesso in modo " +"efficiente\n" +"utilizzerà solo l'API della funzione esterna." + +#: src\patterns/ffi/wrappers.md:79 +#, fuzzy +msgid "### Trying to Wrap Iterators (and Failing)" +msgstr "### Tentativo di avvolgere gli iteratori (e fallire)" + +#: src\patterns/ffi/wrappers.md:81 +#, fuzzy +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 "" +"Per racchiudere correttamente qualsiasi tipo di iteratore nell'API, il " +"wrapper dovrebbe farlo\n" +"fai quello che farebbe una versione C del codice: cancella la durata " +"dell'iteratore,\n" +"e gestirlo manualmente." + +#: src\patterns/ffi/wrappers.md:85 +#, fuzzy +msgid "Suffice it to say, this is _incredibly_ difficult." +msgstr "Basti dire che questo è _incredibilmente_ difficile." + +#: src\patterns/ffi/wrappers.md:87 +#, fuzzy +msgid "Here is an illustration of just _one_ pitfall." +msgstr "Ecco un'illustrazione di una sola trappola." + +#: src\patterns/ffi/wrappers.md:89 +#, fuzzy +msgid "A first version of `MySetWrapper` would look like this:" +msgstr "Una prima versione di `MySetWrapper` sarebbe simile a questa:" + +#: 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 +#, fuzzy +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 "" +"Con `transmute` utilizzato per estendere una durata e un puntatore per " +"nasconderlo,\n" +"è già brutto. Ma c'è di peggio: _qualsiasi altra operazione può causare\n" +"Rust `comportamento indefinito`_." + +#: src\patterns/ffi/wrappers.md:104 +#, fuzzy +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 "" +"Considera che \"MySet\" nel wrapper potrebbe essere manipolato da altri\n" +"funzioni durante l'iterazione, come la memorizzazione di un nuovo valore " +"nella chiave che era\n" +"iterando. L'API non scoraggia questo, e in effetti alcuni simili C\n" +"le biblioteche se lo aspettano." + +#: src\patterns/ffi/wrappers.md:109 +#, fuzzy +msgid "A simple implementation of `myset_store` would be:" +msgstr "Una semplice implementazione di `myset_store` sarebbe:" + +#: 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 +#, fuzzy +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 "" +"Se l'iteratore esiste quando viene chiamata questa funzione, ne abbiamo " +"violato uno di Rust\n" +"regole di aliasing Secondo Rust, il riferimento mutabile in questo blocco " +"deve avere\n" +"accesso _esclusivo_ all'oggetto. Se l'iteratore esiste semplicemente, non è " +"esclusivo,\n" +"quindi abbiamo un `comportamento indefinito`!" + +#: src\patterns/ffi/wrappers.md:142 +#, fuzzy +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 "" +"Per evitare ciò, dobbiamo avere un modo per garantire che il riferimento " +"mutabile sia davvero esclusivo.\n" +"Ciò significa sostanzialmente eliminare il riferimento condiviso " +"dell'iteratore mentre esiste,\n" +"e poi ricostruirlo. Nella maggior parte dei casi, sarà comunque meno " +"efficiente di\n" +"la versione C." + +#: src\patterns/ffi/wrappers.md:147 +#, fuzzy +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 "" +"Alcuni potrebbero chiedere: come può C farlo in modo più efficiente?\n" +"La risposta è che imbroglia. Le regole di aliasing di Rust sono il problema " +"e C semplicemente le ignora\n" +"loro per i suoi puntatori. In cambio, è comune vedere il codice che viene " +"dichiarato\n" +"nel manuale come \"non thread-safe\" in alcune o tutte le circostanze. " +"Infatti,\n" +"la [libreria GNU " +"C](https://manpages.debian.org/buster/manpages/attributes.7.en.html)\n" +"ha un intero lessico dedicato al comportamento concorrente!" + +#: src\patterns/ffi/wrappers.md:154 +#, fuzzy +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 "" +"Rust preferirebbe rendere ogni memoria sempre al sicuro, sia per sicurezza " +"che per\n" +"ottimizzazioni che il codice C non può raggiungere. Viene negato l'accesso a " +"determinate scorciatoie\n" +"è il prezzo che i programmatori di Rust devono pagare." + +#: src\patterns/ffi/wrappers.md:158 +#, fuzzy +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 "" +"Per i programmatori C là fuori che si grattano la testa, l'iteratore ha " +"bisogno\n" +"non essere letto _durante_ questo codice causa l'UB. La regola di " +"esclusività consente anche\n" +"ottimizzazioni del compilatore che possono causare osservazioni incoerenti " +"da parte dell'iteratore\n" +"riferimento condiviso (ad es. stack spill o riordino delle istruzioni per " +"l'efficienza).\n" +"Queste osservazioni possono verificarsi _qualsiasi momento dopo_ la " +"creazione del riferimento mutabile." + +#: src\anti_patterns/index.md:1 +#, fuzzy +msgid "# Anti-patterns" +msgstr "# Anti-modelli" + +#: src\anti_patterns/index.md:3 +#, fuzzy +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 "" +"Un [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern) è una " +"soluzione a\n" +"un \"problema ricorrente che di solito è inefficace e rischia di essere " +"altamente\n" +"controproducente\". Altrettanto prezioso quanto sapere come risolvere un " +"problema, lo è\n" +"sapere come _non_ risolverlo. Gli anti-pattern ci forniscono ottimi " +"contro-esempi\n" +"considerare rispetto ai modelli di progettazione. Gli anti-pattern non sono " +"limitati al codice.\n" +"Ad esempio, anche un processo può essere un anti-pattern." + +#: src\anti_patterns/borrow_clone.md:1 +#, fuzzy +msgid "# Clone to satisfy the borrow checker" +msgstr "# Clona per soddisfare il controllore del prestito" + +#: src\anti_patterns/borrow_clone.md:5 +#, fuzzy +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 "" +"Il controllo del prestito impedisce agli utenti di Rust di sviluppare codice " +"altrimenti non sicuro\n" +"assicurando che: esista un solo riferimento mutabile, o potenzialmente molti " +"ma\n" +"esistono tutti i riferimenti immutabili. Se il codice scritto non è vero per " +"questi\n" +"condizioni, questo anti-pattern si verifica quando lo sviluppatore risolve " +"il compilatore\n" +"errore clonando la variabile." + +#: 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 +#, fuzzy +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 "" +"È allettante, in particolare per i principianti, utilizzare questo schema " +"per risolvere\n" +"problemi di confusione con il controllo del prestito. Tuttavia, ci sono " +"gravi\n" +"conseguenze. L'uso di `.clone()` provoca la creazione di una copia dei dati. " +"Eventuali modifiche\n" +"tra i due non sono sincronizzati -- come se due variabili completamente " +"separate\n" +"esistere." + +#: src\anti_patterns/borrow_clone.md:38 +#, fuzzy +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 "" +"Ci sono casi speciali -- `Rc` è progettato per gestire i cloni in modo " +"intelligente.\n" +"Gestisce internamente esattamente una copia dei dati e la clonazione lo farà " +"solo\n" +"clonare il riferimento." + +#: src\anti_patterns/borrow_clone.md:42 +#, fuzzy +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 "" +"C'è anche `Arc` che fornisce la proprietà condivisa di un valore di tipo " +"T\n" +"allocato nell'heap. Invocare `.clone()` su `Arc` produce un nuovo `Arc`\n" +"istanza, che punta alla stessa allocazione sull'heap della sorgente `Arc`,\n" +"durante l'aumento di un conteggio di riferimento." + +#: src\anti_patterns/borrow_clone.md:47 +#, fuzzy +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 "" +"In generale, i cloni dovrebbero essere deliberati, con piena comprensione " +"del\n" +"conseguenze. Se viene utilizzato un clone per far scomparire un errore di " +"verifica del prestito,\n" +"questa è una buona indicazione che questo anti-pattern potrebbe essere in " +"uso." + +#: src\anti_patterns/borrow_clone.md:51 +#, fuzzy +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 "" +"Anche se `.clone()` è un'indicazione di uno schema errato, a volte\n" +"**va bene scrivere codice inefficiente**, in casi come quando:" + +#: src\anti_patterns/borrow_clone.md:54 +#, fuzzy +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 "" +"- lo sviluppatore è ancora nuovo alla proprietà\n" +"- il codice non ha grandi velocità o vincoli di memoria\n" +" (come progetti di hackathon o prototipi)\n" +"- soddisfare il controllore del prestito è davvero complicato e preferisci " +"farlo\n" +" ottimizzare la leggibilità rispetto alle prestazioni" + +#: src\anti_patterns/borrow_clone.md:60 +#, fuzzy +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 "" +"Se si sospetta un clone non necessario, il [capitolo sulla proprietà di Rust " +"Book](https://doc.rust-lang.org/book/ownership.html)\n" +"dovrebbe essere compreso appieno prima di valutare se il clone è necessario " +"o meno." + +#: src\anti_patterns/borrow_clone.md:63 +#, fuzzy +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 "" +"Assicurati anche di eseguire sempre `cargo clippy` nel tuo progetto, che ne " +"rileverà alcuni\n" +"casi in cui `.clone()` non è necessario, come " +"[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) o " +"[4](https://rust-lang.github.io/rust-clippy/master " +"/index.html#clone_double_ref)." + +#: src\anti_patterns/borrow_clone.md:70 +#, fuzzy +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 "" +"- [`mem::{take(_), replace(_)}` per mantenere i valori di proprietà nelle " +"enum modificate](../idioms/mem-replace.md)\n" +"- [documentazione `Rc`, che gestisce .clone() in modo " +"intelligente](http://doc.rust-lang.org/std/rc/)\n" +"- [documentazione `Arc`, un puntatore thread-safe per il conteggio dei " +"riferimenti](https://doc.rust-lang.org/std/sync/struct.Arc.html)\n" +"- [Trucchi con la proprietà in " +"Rust](https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html)" + +#: src\anti_patterns/deny-warnings.md:1 +#, fuzzy +msgid "# `#![deny(warnings)]`" +msgstr "# `#![nega(avvisi)]`" + +#: src\anti_patterns/deny-warnings.md:5 +#, fuzzy +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 "" +"Un autore di casse ben intenzionato vuole assicurarsi che il proprio codice " +"venga compilato senza\n" +"avvertimenti. Quindi annotano la loro radice di cassa con quanto segue:" + +#: 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 +#, fuzzy +msgid "It is short and will stop the build if anything is amiss." +msgstr "È breve e interromperà la compilazione se qualcosa non va." + +#: src\anti_patterns/deny-warnings.md:20 +#, fuzzy +msgid "## Drawbacks" +msgstr "## Svantaggi" + +#: src\anti_patterns/deny-warnings.md:22 +#, fuzzy +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 "" +"Impedendo al compilatore di compilare con avvertimenti, un autore di crate " +"rinuncia\n" +"La famosa stabilità di Rust. A volte nuove funzionalità o vecchie " +"funzionalità errate richiedono un cambiamento\n" +"nel modo in cui si fanno le cose, così si scrive lanugine che 'avvertono' " +"per una certa grazia\n" +"periodo prima di essere trasformato in \"deny\"." + +#: src\anti_patterns/deny-warnings.md:27 +#, fuzzy +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 "" +"Ad esempio, è stato scoperto che un tipo potrebbe avere due `impl` con lo " +"stesso\n" +"metodo. Questa è stata considerata una cattiva idea, ma per facilitare la " +"transizione,\n" +"il lint `overlapping-inherent-impls` è stato introdotto per dare un " +"avvertimento a quelli\n" +"inciampando su questo fatto, prima che diventi un grave errore in una " +"versione futura." + +#: src\anti_patterns/deny-warnings.md:32 +#, fuzzy +msgid "" +"Also sometimes APIs get deprecated, so their use will emit a warning where\n" +"before there was none." +msgstr "" +"Inoltre, a volte le API vengono deprecate, quindi il loro utilizzo emetterà " +"un avviso dove\n" +"prima non ce n'era nessuno." + +#: src\anti_patterns/deny-warnings.md:35 +#, fuzzy +msgid "" +"All this conspires to potentially break the build whenever something changes." +msgstr "" +"Tutto ciò cospira potenzialmente per interrompere la build ogni volta che " +"qualcosa cambia." + +#: src\anti_patterns/deny-warnings.md:37 +#, fuzzy +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 "" +"Inoltre, le casse che forniscono pelucchi aggiuntivi (ad es. " +"[ruggine-clippy]) non possono\n" +"essere più utilizzato a meno che l'annotazione non venga rimossa. Questo è " +"mitigato con\n" +"[--cap-pelucchi]. L'argomento della riga di comando `--cap-lints=warn` " +"trasforma tutto in `deny`\n" +"errori di lint in avvisi." + +#: src\anti_patterns/deny-warnings.md:42 +#: src\functional/generics-type-classes.md:227 +#, fuzzy +msgid "## Alternatives" +msgstr "## Alternative" + +#: src\anti_patterns/deny-warnings.md:44 +#, fuzzy +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 "" +"Ci sono due modi per affrontare questo problema: in primo luogo, possiamo " +"disaccoppiare la build\n" +"impostazione dal codice e, in secondo luogo, possiamo nominare i lint che " +"vogliamo negare\n" +"esplicitamente." + +#: src\anti_patterns/deny-warnings.md:48 +#, fuzzy +msgid "The following command line will build with all warnings set to `deny`:" +msgstr "" +"La seguente riga di comando verrà compilata con tutti gli avvisi impostati " +"su \"deny\":" + +#: src\anti_patterns/deny-warnings.md:50 +#, fuzzy +msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" +msgstr "`RUSTFLAGS=\"-D warnings\" costruzione del carico`" + +#: src\anti_patterns/deny-warnings.md:52 +#, fuzzy +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 "" +"Questo può essere fatto da qualsiasi singolo sviluppatore (o essere " +"impostato in uno strumento CI come\n" +"Travis, ma ricorda che questo potrebbe interrompere la build quando qualcosa " +"cambia)\n" +"senza richiedere una modifica al codice." + +#: src\anti_patterns/deny-warnings.md:56 +#, fuzzy +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 "" +"In alternativa, possiamo specificare i lint che vogliamo \"negare\" nel " +"codice.\n" +"Ecco un elenco di avvertenze che è (si spera) sicuro negare (a partire da " +"Rustc 1.48.0):" + +#: 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 +#, fuzzy +msgid "In addition, the following `allow`ed lints may be a good idea to `deny`:" +msgstr "" +"Inoltre, i seguenti lint \"consentiti\" possono essere una buona idea da " +"\"negare\":" + +#: 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 +#, fuzzy +msgid "Some may also want to add `missing-copy-implementations` to their list." +msgstr "" +"Alcuni potrebbero anche voler aggiungere `missing-copy-implementations` alla " +"loro lista." + +#: src\anti_patterns/deny-warnings.md:93 +#, fuzzy +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 "" +"Si noti che non abbiamo esplicitamente aggiunto il lint `deprecato`, poiché " +"è corretto\n" +"certi che in futuro ci saranno più API obsolete." + +#: src\anti_patterns/deny-warnings.md:98 +#, fuzzy +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 "" +"- [Una raccolta di tutti i pelucchi " +"clippy](https://rust-lang.github.io/rust-clippy/master)\n" +"- [attributo obsoleto] documentazione\n" +"- Digita `rustc -W help` per un elenco di lint sul tuo sistema. Digita " +"anche\n" +" `rustc --help` per un elenco generale di opzioni\n" +"- [rust-clippy] è una raccolta di lanugine per migliorare il codice Rust" + +#: src\anti_patterns/deref.md:1 +#, fuzzy +msgid "# `Deref` polymorphism" +msgstr "# Polimorfismo `Deref`" + +#: src\anti_patterns/deref.md:5 +#, fuzzy +msgid "" +"Misuse the `Deref` trait to emulate inheritance between structs, and thus " +"reuse\n" +"methods." +msgstr "" +"Usa in modo improprio il tratto `Deref` per emulare l'ereditarietà tra " +"struct e quindi riutilizzarlo\n" +"metodi." + +#: src\anti_patterns/deref.md:10 +#, fuzzy +msgid "" +"Sometimes we want to emulate the following common pattern from OO languages " +"such\n" +"as Java:" +msgstr "" +"A volte vogliamo emulare il seguente modello comune da linguaggi OO come\n" +"come Java:" + +#: 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 +#, fuzzy +msgid "We can use the deref polymorphism anti-pattern to do so:" +msgstr "Possiamo usare l'anti-pattern del polimorfismo deref per farlo:" + +#: 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 +#, fuzzy +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 "" +"Non c'è ereditarietà struct in Rust. Usiamo invece composizione e " +"inclusione\n" +"un'istanza di `Foo` in `Bar` (poiché il campo è un valore, viene memorizzato " +"in linea,\n" +"quindi se ci fossero campi, avrebbero lo stesso layout in memoria di Java\n" +"versione (probabilmente, dovresti usare `#[repr(C)]` se vuoi essere sicuro))." + +#: src\anti_patterns/deref.md:61 +#, fuzzy +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 "" +"Per far funzionare la chiamata al metodo, implementiamo `Deref` per `Bar` " +"con `Foo`\n" +"come destinazione (restituendo il campo `Foo` incorporato). Ciò significa " +"che quando noi\n" +"dereferenziare un `Bar` (ad esempio, utilizzando `*`), otterremo un `Foo`. " +"Questo è\n" +"abbastanza strano. La dereferenziazione di solito dà una \"T\" da un " +"riferimento a \"T\", qui noi\n" +"hanno due tipi non correlati. Tuttavia, poiché l'operatore punto fa " +"implicit\n" +"dereferenziando, significa che la chiamata al metodo cercherà i metodi su " +"`Foo` as\n" +"così come \"Bar\"." + +#: src\anti_patterns/deref.md:71 +#, fuzzy +msgid "You save a little boilerplate, e.g.," +msgstr "Risparmi un po' di standard, ad esempio," + +#: 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 +#, fuzzy +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 "" +"La cosa più importante è che questo è un linguaggio sorprendente: i futuri " +"programmatori lo leggono\n" +"il codice non si aspetterà che ciò accada. Questo perché stiamo abusando del " +"`Deref`\n" +"tratto piuttosto che usarlo come previsto (e documentato, ecc.). È anche " +"perché\n" +"il meccanismo qui è del tutto implicito." + +#: src\anti_patterns/deref.md:88 +#, fuzzy +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 "" +"Questo modello non introduce il sottotipo tra `Foo` e `Bar` come\n" +"l'ereditarietà in Java o C++ lo fa. Inoltre, i tratti implementati da " +"\"Foo\" lo sono\n" +"non implementato automaticamente per `Bar`, quindi questo modello " +"interagisce male con\n" +"controllo dei limiti e quindi programmazione generica." + +#: src\anti_patterns/deref.md:93 +#, fuzzy +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 "" +"L'uso di questo modello fornisce una semantica leggermente diversa dalla " +"maggior parte dei linguaggi OO con\n" +"riguardo a \"sé\". Di solito rimane un riferimento alla sottoclasse, con " +"questo\n" +"pattern sarà la 'classe' in cui è definito il metodo." + +#: src\anti_patterns/deref.md:97 +#, fuzzy +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 "" +"Infine, questo modello supporta solo l'ereditarietà singola e non ha alcuna " +"nozione di\n" +"interfacce, privacy basata su classi o altre funzionalità relative " +"all'ereditarietà. Quindi, esso\n" +"offre un'esperienza che sarà sottilmente sorprendente per i programmatori " +"abituati a Java\n" +"eredità, ecc." + +#: src\anti_patterns/deref.md:104 +#, fuzzy +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 "" +"Non esiste una buona alternativa. A seconda delle circostanze esatte " +"potrebbe\n" +"sarebbe meglio reimplementare usando i tratti o scrivere i metodi di " +"facciata a\n" +"invia a `Foo` manualmente. Intendiamo aggiungere un meccanismo per " +"l'ereditarietà\n" +"simile a questo per Rust, ma è probabile che ci voglia del tempo prima che " +"raggiunga\n" +"Ruggine stabile. Vedi questi " +"[blog](http://aturon.github.io/blog/2015/09/18/reuse/)\n" +"[post](http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/)\n" +"e questo [problema RFC](https://github.com/rust-lang/rfcs/issues/349) per " +"maggiori dettagli." + +#: src\anti_patterns/deref.md:112 +#, fuzzy +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 "" +"Il tratto `Deref` è progettato per l'implementazione di tipi di puntatore " +"personalizzati.\n" +"L'intenzione è che prenderà un puntatore a `T` in una `T`, non convertirà\n" +"tra tipi diversi. È un peccato che questo non sia (probabilmente non può " +"essere)\n" +"imposto dalla definizione di tratto." + +#: src\anti_patterns/deref.md:117 +#, fuzzy +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 "" +"Rust cerca di trovare un attento equilibrio tra meccanismi espliciti e " +"impliciti,\n" +"favorendo conversioni esplicite tra i tipi. Dereferenziazione automatica nel " +"punto\n" +"operatore è un caso in cui l'ergonomia favorisce fortemente un meccanismo " +"implicito,\n" +"ma l'intenzione è che questo sia limitato a gradi di indirezione, no\n" +"conversione tra tipi arbitrari." + +#: src\anti_patterns/deref.md:125 +#, fuzzy +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 "" +"- [Le raccolte sono idiomi di puntatori intelligenti](../idioms/deref.md).\n" +"- Casse di delega per meno boilerplate come " +"[delegate](https://crates.io/crates/delegate)\n" +" o [ambasciatore](https://crates.io/crates/ambassador)\n" +"- [Documentazione per il tratto " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\functional/index.md:1 +#, fuzzy +msgid "# Functional Usage of Rust" +msgstr "# Utilizzo funzionale di Rust" + +#: src\functional/index.md:3 +#, fuzzy +msgid "" +"Rust is an imperative language, but it follows many\n" +"[functional " +"programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms." +msgstr "" +"Rust è un linguaggio imperativo, ma ne segue molti\n" +"[programmazione " +"funzionale](https://en.wikipedia.org/wiki/Functional_programming) paradigmi." + +#: src\functional/index.md:6 +#, fuzzy +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 "" +"> In informatica, la _programmazione funzionale_ è un paradigma di " +"programmazione in cui\n" +"> i programmi sono costruiti applicando e componendo funzioni.\n" +"> È un paradigma di programmazione dichiarativo in cui le definizioni di " +"funzione sono\n" +"> alberi di espressioni che restituiscono ciascuno un valore, piuttosto che " +"una sequenza di\n" +"> affermazioni imperative che cambiano lo stato del programma." + +#: src\functional/paradigms.md:1 +#, fuzzy +msgid "# Programming paradigms" +msgstr "# Paradigmi di programmazione" + +#: src\functional/paradigms.md:3 +#, fuzzy +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 "" +"Uno dei maggiori ostacoli alla comprensione dei programmi funzionali in " +"arrivo\n" +"da uno sfondo imperativo è il cambiamento nel pensiero. Programmi " +"imperativi\n" +"descrivono **come** fare qualcosa, mentre i programmi dichiarativi " +"descrivono\n" +"**cosa fare. Sommiamo i numeri da 1 a 10 per mostrarlo." + +#: src\functional/paradigms.md:8 +#, fuzzy +msgid "## Imperative" +msgstr "## Imperativo" + +#: 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 +#, fuzzy +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 "" +"Con i programmi imperativi, dobbiamo giocare al compilatore per vedere cosa " +"sta succedendo.\n" +"Qui, iniziamo con una \"somma\" di \"0\".\n" +"Successivamente, iteriamo attraverso l'intervallo da 1 a 10.\n" +"Ogni volta attraverso il ciclo, aggiungiamo il valore corrispondente " +"nell'intervallo.\n" +"Quindi lo stampiamo." + +#: src\functional/paradigms.md:24 +#, fuzzy +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 "" +"| `io` | `somma` |\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|" + +#: src\functional/paradigms.md:37 +#, fuzzy +msgid "" +"This is how most of us start out programming. We learn that a program is a " +"set\n" +"of steps." +msgstr "" +"Questo è il modo in cui la maggior parte di noi inizia a programmare. " +"Impariamo che un programma è un insieme\n" +"di passi." + +#: src\functional/paradigms.md:40 +#, fuzzy +msgid "## Declarative" +msgstr "## Dichiarativo" + +#: src\functional/paradigms.md:42 +msgid "" +"```rust\n" +"println!(\"{}\", (1..11).fold(0, |a, b| a + b));\n" +"```" +msgstr "" + +#: src\functional/paradigms.md:46 +#, fuzzy +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 "" +"Ehi! Questo è davvero diverso! Cosa sta succedendo qui?\n" +"Ricorda che con i programmi dichiarativi stiamo descrivendo **cosa** fare,\n" +"piuttosto che **come** farlo. `fold` è una funzione che " +"[compone](https://en.wikipedia.org/wiki/Function_composition)\n" +"funzioni. Il nome è una convenzione di Haskell." + +#: src\functional/paradigms.md:51 +#, fuzzy +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 "" +"Qui stiamo componendo funzioni di addizione (questa chiusura: `|a, b| a + " +"b`)\n" +"con un intervallo da 1 a 10. Lo \"0\" è il punto di partenza, quindi \"a\" è " +"\"0\" a\n" +"Primo. \"b\" è il primo elemento dell'intervallo, \"1\". `0 + 1 = 1` è il " +"risultato.\n" +"Quindi ora `pieghiamo` di nuovo, con `a = 1`, `b = 2` e quindi `1 + 2 = 3` è " +"il prossimo\n" +"risultato. Questo processo continua finché non arriviamo all'ultimo elemento " +"dell'intervallo,\n" +"`10`." + +#: src\functional/paradigms.md:58 +#, fuzzy +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 "" +"| `a` | `b` | risultato |\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/generics-type-classes.md:1 +#, fuzzy +msgid "# Generics as Type Classes" +msgstr "# Generics come classi di tipo" + +#: src\functional/generics-type-classes.md:5 +#, fuzzy +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 "" +"Il sistema di tipi di Rust è progettato più come linguaggi funzionali (come " +"Haskell)\n" +"piuttosto che linguaggi imperativi (come Java e C++). Di conseguenza, Rust " +"può trasformarsi\n" +"molti tipi di problemi di programmazione in problemi di \"tipizzazione " +"statica\". Questo è uno\n" +"delle più grandi vittorie nella scelta di un linguaggio funzionale ed è " +"fondamentale per molti\n" +"delle garanzie di tempo di compilazione di Rust." + +#: src\functional/generics-type-classes.md:11 +#, fuzzy +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 "" +"Una parte fondamentale di questa idea è il modo in cui funzionano i tipi " +"generici. In C++ e Java, per\n" +"esempio, i tipi generici sono un costrutto di metaprogrammazione per il " +"compilatore.\n" +"`vector` e `vector` in C++ sono solo due copie diverse di\n" +"stesso codice boilerplate per un tipo `vettoriale` (noto come `template`) " +"con due\n" +"diversi tipi compilati." + +#: src\functional/generics-type-classes.md:17 +#, fuzzy +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 "" +"In Rust, un parametro di tipo generico crea ciò che è noto nei linguaggi " +"funzionali\n" +"come \"vincolo di classe di tipo\" e ogni diverso parametro riempito da una " +"fine\n" +"l'utente _effettivamente cambia il tipo_. In altre parole, `Vec` e " +"`Vec`\n" +"_sono due tipi diversi_, che sono riconosciuti come distinti da tutte le " +"parti del\n" +"sistema tipo." + +#: src\functional/generics-type-classes.md:23 +#, fuzzy +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 "" +"Questo è chiamato **monomorfizzazione**, da cui vengono creati diversi tipi\n" +"codice **polimorfico**. Questo comportamento speciale richiede la " +"specificazione dei blocchi \"impl\".\n" +"parametri generici. Valori diversi per il tipo generico causano tipi " +"diversi,\n" +"e diversi tipi possono avere diversi blocchi `impl`." + +#: src\functional/generics-type-classes.md:28 +#, fuzzy +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 "" +"Nei linguaggi orientati agli oggetti, le classi possono ereditare il " +"comportamento dai loro genitori.\n" +"Tuttavia, ciò consente l'attaccamento non solo di comportamenti aggiuntivi " +"a\n" +"membri particolari di una classe di tipo, ma anche un comportamento extra." + +#: src\functional/generics-type-classes.md:32 +#, fuzzy +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 "" +"L'equivalente più vicino è il polimorfismo di runtime in Javascript e " +"Python,\n" +"dove i nuovi membri possono essere aggiunti agli oggetti volenti o nolenti " +"da qualsiasi costruttore.\n" +"Tuttavia, a differenza di questi linguaggi, tutti i metodi aggiuntivi di " +"Rust possono essere digitati\n" +"controllati quando vengono utilizzati, perché i loro generici sono definiti " +"staticamente. Quello\n" +"li rende più utilizzabili pur rimanendo al sicuro." + +#: src\functional/generics-type-classes.md:40 +#, fuzzy +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 "" +"Si supponga di progettare un server di archiviazione per una serie di " +"computer da laboratorio.\n" +"A causa del software coinvolto, sono necessari due diversi protocolli\n" +"per supportare: BOOTP (per l'avvio di rete PXE) e NFS (per l'archiviazione " +"di montaggio remoto)." + +#: src\functional/generics-type-classes.md:44 +#, fuzzy +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 "" +"Il tuo obiettivo è avere un programma, scritto in Rust, in grado di gestirli " +"entrambi\n" +"loro. Avrà gestori di protocollo e ascolterà entrambi i tipi di richieste. " +"IL\n" +"la logica dell'applicazione principale consentirà quindi a un amministratore " +"di laboratorio di configurare l'archiviazione\n" +"e controlli di sicurezza per i file effettivi." + +#: src\functional/generics-type-classes.md:49 +#, fuzzy +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 "" +"Le richieste di file dalle macchine nel laboratorio contengono la stessa " +"base\n" +"informazioni, indipendentemente dal protocollo da cui provengono: un metodo " +"di autenticazione,\n" +"e un nome file da recuperare. Sembrerebbe un'implementazione semplice\n" +"qualcosa come questo:" + +#: 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 +#, fuzzy +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 "" +"Questo design potrebbe funzionare abbastanza bene. Ma ora supponiamo di aver " +"bisogno di supporto\n" +"aggiunta di metadati che erano _protocol specific_. Ad esempio, con NFS, tu\n" +"voleva determinare quale fosse il loro punto di montaggio per applicare " +"ulteriori\n" +"regole di sicurezza." + +#: src\functional/generics-type-classes.md:71 +#, fuzzy +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 "" +"Il modo in cui è progettata la struttura corrente lascia la decisione del " +"protocollo fino a quando\n" +"tempo di esecuzione. Ciò significa qualsiasi metodo che si applica a un " +"protocollo e non all'altro\n" +"richiede al programmatore di eseguire un controllo di runtime." + +#: src\functional/generics-type-classes.md:75 +#, fuzzy +msgid "Here is how getting an NFS mount point would look:" +msgstr "Ecco come sarebbe ottenere un punto di montaggio NFS:" + +#: 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 +#, fuzzy +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 "" +"Ogni chiamante di `mount_point()` deve verificare la presenza di `None` e " +"scrivere il codice da gestire\n" +"Esso. Questo è vero anche se sanno che solo le richieste NFS vengono " +"utilizzate in un dato dato\n" +"percorso del codice!" + +#: src\functional/generics-type-classes.md:99 +#, fuzzy +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 "" +"Sarebbe molto più ottimale causare un errore in fase di compilazione se il " +"diverso\n" +"i tipi di richiesta erano confusi. Dopo tutto, l'intero percorso del codice " +"dell'utente,\n" +"comprese le funzioni della libreria che usano, sapranno se una richiesta\n" +"è una richiesta NFS o una richiesta BOOTP." + +#: src\functional/generics-type-classes.md:104 +#, fuzzy +msgid "" +"In Rust, this is actually possible! The solution is to _add a generic type_ " +"in\n" +"order to split the API." +msgstr "" +"In Rust, questo è effettivamente possibile! La soluzione è _aggiungere un " +"tipo generico_ in\n" +"per dividere l'API." + +#: src\functional/generics-type-classes.md:107 +#, fuzzy +msgid "Here is what that looks like:" +msgstr "Ecco come appare:" + +#: 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 +#, fuzzy +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 "" +"Otterrebbero un errore di sintassi. Il tipo `FileDownloadRequest` no\n" +"implementa `mount_point()`, solo il tipo `FileDownloadRequest` lo fa. " +"E\n" +"creato dal modulo NFS, non dal modulo BOOTP ovviamente!" + +#: src\functional/generics-type-classes.md:212 +#, fuzzy +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 "" +"Innanzitutto, consente di deduplicare i campi comuni a più stati.\n" +"Rendendo generici i campi non condivisi, questi vengono implementati una " +"volta." + +#: src\functional/generics-type-classes.md:215 +#, fuzzy +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 "" +"In secondo luogo, rende i blocchi `impl` più facili da leggere, perché sono " +"scomposti\n" +"per stato. I metodi comuni a tutti gli stati vengono digitati una volta in " +"un blocco e i metodi\n" +"univoci per uno stato si trovano in un blocco separato." + +#: src\functional/generics-type-classes.md:219 +#, fuzzy +msgid "" +"Both of these mean there are fewer lines of code, and they are better " +"organized." +msgstr "" +"Entrambi significano che ci sono meno righe di codice e sono meglio " +"organizzati." + +#: src\functional/generics-type-classes.md:223 +#, fuzzy +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 "" +"Questo attualmente aumenta la dimensione del binario, a causa del modo in " +"cui monomorfizzazione\n" +"è implementato nel compilatore. Speriamo che l'attuazione sarà in grado di\n" +"migliorare in futuro." + +#: src\functional/generics-type-classes.md:229 +#, fuzzy +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 "" +"- Se un tipo sembra aver bisogno di una \"split API\" a causa della " +"costruzione o parziale\n" +" inizializzazione, considerare il\n" +" [Builder Pattern](../patterns/creational/builder.md) invece.\n" +"\n" +"- Se l'API tra i tipi non cambia, solo il comportamento cambia, allora\n" +" il [Strategy Pattern](../patterns/behavioural/strategy.md) è meglio usato\n" +" Invece." + +#: src\functional/generics-type-classes.md:239 +#, fuzzy +msgid "This pattern is used throughout the standard library:" +msgstr "Questo modello è utilizzato in tutta la libreria standard:" + +#: src\functional/generics-type-classes.md:241 +#, fuzzy +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 "" +"- `Vec` può essere lanciato da una stringa, a differenza di ogni altro " +"tipo di `Vec`.[^1]\n" +"- Possono anche essere inseriti in un heap binario, ma solo se contengono un " +"tipo\n" +" che implementa il tratto `Ord`.[^2]\n" +"- Il metodo `to_string` era specializzato per `Cow` solo di tipo `str`.[^3]" + +#: src\functional/generics-type-classes.md:246 +#, fuzzy +msgid "It is also used by several popular crates to allow API flexibility:" +msgstr "" +"Viene anche utilizzato da diverse casse popolari per consentire la " +"flessibilità dell'API:" + +#: src\functional/generics-type-classes.md:248 +#, fuzzy +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 "" +"- L'ecosistema `embedded-hal` utilizzato per i dispositivi embedded fa ampio " +"uso di\n" +" questo modello. Ad esempio, consente di verificare staticamente la " +"configurazione di\n" +" registri del dispositivo utilizzati per controllare i pin incorporati. " +"Quando un pin viene messo in una modalità,\n" +" restituisce una struttura `Pin`, il cui generico determina le " +"funzioni\n" +" utilizzabili in quella modalità, che non sono sul `Pin` stesso. [^4]\n" +"\n" +"- La libreria client `hyper` HTTP utilizza questo per esporre ricche API per " +"diversi\n" +" richieste collegabili. I client con connettori diversi hanno metodi " +"diversi\n" +" su di essi così come diverse implementazioni di tratti, mentre un set di " +"base di\n" +" metodi si applicano a qualsiasi connettore. [^5]\n" +"\n" +"- Il modello \"tipo stato\" -- in cui un oggetto guadagna e perde l'API in " +"base a un\n" +" stato interno o invariante -- è implementato in Rust usando la stessa " +"base\n" +" concetto e una tecnica leggermente diversa. [^6]" + +#: src\functional/generics-type-classes.md:263 +#, fuzzy +msgid "" +"See: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811)" +msgstr "" +"Vedere: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811 " +")" + +#: src\functional/generics-type-classes.md:265 +#, fuzzy +msgid "" +"See: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354)" +msgstr "" +"Vedere: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections " +"/binary_heap.rs.html#1345-1354)" + +#: src\functional/generics-type-classes.md:267 +#, fuzzy +msgid "" +"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240)" +msgstr "" +"Vedi: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235- 2240)" + +#: src\functional/generics-type-classes.md:269 +#, fuzzy +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 "" +"Esempio:\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/generics-type-classes.md:272 +#, fuzzy +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 "" +"Vedere:\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/generics-type-classes.md:275 +#, fuzzy +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 "" +"Vedere:\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" +"E\n" +"[Rusty Typestate Series (una tesi " +"estesa)](https://web.archive.org/web/20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index " +")" + +#: src\functional/lenses.md:1 +#, fuzzy +msgid "# Lenses and Prisms" +msgstr "# Lenti e prismi" + +#: src\functional/lenses.md:3 +#, fuzzy +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 "" +"Questo è un puro concetto funzionale che non viene usato frequentemente in " +"Rust.\n" +"Tuttavia, esplorare il concetto può essere utile per capirne altri\n" +"pattern nelle API di Rust, come " +"[visitors](../patterns/behavioural/visitor.md).\n" +"Hanno anche casi d'uso di nicchia." + +#: src\functional/lenses.md:8 +#, fuzzy +msgid "## Lenses: Uniform Access Across Types" +msgstr "## Lenti: accesso uniforme tra i tipi" + +#: src\functional/lenses.md:10 +#, fuzzy +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 "" +"Una lente è un concetto dei linguaggi di programmazione funzionale che " +"consente\n" +"accedere a parti di un tipo di dati in modo astratto e unificato.[^1]\n" +"Nel concetto di base, è simile al modo in cui i tratti di Rust funzionano " +"con la cancellazione del tipo,\n" +"ma ha un po' più di potenza e flessibilità." + +#: src\functional/lenses.md:15 +#, fuzzy +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 "" +"Ad esempio, supponiamo che una banca contenga diversi formati JSON per il " +"cliente\n" +"dati.\n" +"Questo perché provengono da diversi database o sistemi legacy.\n" +"Un database contiene i dati necessari per eseguire i controlli del credito:" + +#: 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 +#, fuzzy +msgid "Another one contains the account information:" +msgstr "Un altro contiene le informazioni sull'account:" + +#: 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 +#, fuzzy +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 "" +"Si noti che entrambi i tipi hanno un numero ID cliente che corrisponde a una " +"persona.\n" +"In che modo una singola funzione gestirà entrambi i record di tipi diversi?" + +#: src\functional/lenses.md:50 +#, fuzzy +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 "" +"In Rust, una `struct` potrebbe rappresentare ciascuno di questi tipi e un " +"tratto lo farebbe\n" +"una funzione `get_customer_id` che implementerebbero:" + +#: 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 +#, fuzzy +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 "" +"Le lenti, tuttavia, consentono di spostare il codice che supporta l'ID " +"cliente dal file\n" +"_type_ alla _funzione di accesso_.\n" +"Invece di implementare un tratto su ciascun tipo, tutte le strutture " +"corrispondenti possono farlo\n" +"essere semplicemente accessibile allo stesso modo." + +#: src\functional/lenses.md:109 +#, fuzzy +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 "" +"Anche se il linguaggio Rust stesso non lo supporta (la cancellazione del " +"tipo è il file\n" +"soluzione preferita a questo problema), il [lens-rs " +"crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) consente il " +"codice\n" +"che sembra così da scrivere con le macro:" + +#: 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 +#, fuzzy +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 "" +"La versione di `unique_ids_lens` mostrata qui consente a qualsiasi tipo di " +"essere nell'iteratore,\n" +"fintanto che ha un attributo chiamato `customer_id` a cui è possibile " +"accedere\n" +"la funzione.\n" +"Questo è il modo in cui la maggior parte dei linguaggi di programmazione " +"funzionali opera sugli obiettivi." + +#: src\functional/lenses.md:154 +#, fuzzy +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 "" +"Piuttosto che macro, ottengono questo risultato con una tecnica nota come " +"\"currying\".\n" +"Cioè, \"costruiscono parzialmente\" la funzione, lasciando il tipo di\n" +"parametro finale (il valore su cui si sta operando) vuoto finché la funzione " +"non lo è\n" +"chiamato.\n" +"Quindi può essere chiamato dinamicamente con tipi diversi anche da un posto " +"all'interno\n" +"il codice.\n" +"Questo è ciò che simulano `optics!` e `view_ref` nell'esempio precedente." + +#: src\functional/lenses.md:162 +#, fuzzy +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 "" +"L'approccio funzionale non deve essere limitato all'accesso ai membri.\n" +"È possibile creare lenti più potenti che sia _set_ che _get_ dati in a\n" +"struttura.\n" +"Ma il concetto diventa davvero interessante se usato come elemento " +"costitutivo per\n" +"composizione.\n" +"È qui che il concetto appare più chiaramente in Rust." + +#: src\functional/lenses.md:169 +#, fuzzy +msgid "## Prisms: A Higher-Order form of \"Optics\"" +msgstr "## Prismi: una forma di \"ottica\" di ordine superiore" + +#: src\functional/lenses.md:171 +#, fuzzy +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 "" +"Una semplice funzione come `unique_ids_lens` sopra opera su un singolo " +"obiettivo.\n" +"Un _prisma_ è una funzione che opera su una _famiglia_ di lenti.\n" +"È un livello concettuale più alto, usando le lenti come elemento " +"costitutivo, e\n" +"continuando la metafora, fa parte di una famiglia di \"ottiche\".\n" +"È il principale utile per comprendere le API di Rust, così come lo sarà il\n" +"concentrati qui." + +#: src\functional/lenses.md:178 +#, fuzzy +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 "" +"Allo stesso modo in cui i tratti consentono un design \"simile a una lente\" " +"con polimorfismo statico e\n" +"invio dinamico, i design simili a prismi appaiono nelle API di Rust che " +"suddividono i problemi\n" +"in più tipi associati da comporre.\n" +"Un buon esempio di ciò sono i tratti nella cassa di analisi _Serde_." + +#: src\functional/lenses.md:183 +#, fuzzy +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 "" +"Cercare di capire il modo in cui funziona _Serde_ leggendo solo l'API è un\n" +"sfida, soprattutto la prima volta.\n" +"Considera il tratto `Deserializer`, implementato da qualche tipo in " +"qualsiasi libreria\n" +"che analizza un nuovo formato:" + +#: 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 +#, fuzzy +msgid "" +"For a trait that is just supposed to parse data from a format and return a\n" +"value, this looks odd." +msgstr "" +"Per un tratto che dovrebbe solo analizzare i dati da un formato e restituire " +"a\n" +"valore, questo sembra strano." + +#: src\functional/lenses.md:207 +#, fuzzy +msgid "Why are all the return types type erased?" +msgstr "Perché tutti i tipi restituiti vengono cancellati?" + +#: src\functional/lenses.md:209 +#, fuzzy +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 "" +"Per capirlo, dobbiamo tenere a mente il concetto di obiettivo e guardare\n" +"la definizione del tipo `Visitor` che viene passata genericamente:" + +#: 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 +#, fuzzy +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 "" +"Il compito del tipo `Visitor` è costruire valori nel modello di dati " +"_Serde_,\n" +"che sono rappresentati dal tipo \"Valore\" associato." + +#: src\functional/lenses.md:235 +#, fuzzy +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 "" +"Questi valori rappresentano parti del valore Rust che vengono " +"deserializzate.\n" +"Se fallisce, restituisce un tipo `Error` - un tipo di errore determinato dal " +"file\n" +"`Deserializer` quando sono stati chiamati i suoi metodi." + +#: src\functional/lenses.md:239 +#, fuzzy +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 "" +"Ciò evidenzia che \"Deserializer\" è simile a \"CustomerId\" di prima,\n" +"consentendo a qualsiasi parser di formato che lo implementa di creare " +"`Valori` in base a cosa\n" +"ha analizzato.\n" +"Il tratto \"Valore\" agisce come una lente nei linguaggi di programmazione " +"funzionale." + +#: src\functional/lenses.md:244 +#, fuzzy +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 "" +"Ma a differenza del tratto `CustomerId`, i tipi restituiti dei metodi " +"`Visitor` lo sono\n" +"_generico_, e il tipo `Valore` concreto è _determinato dal Visitatore " +"stesso_." + +#: src\functional/lenses.md:247 +#, fuzzy +msgid "" +"Instead of acting as one lens, it effectively acts as a family of\n" +"lenses, one for each concrete type of `Visitor`." +msgstr "" +"Invece di agire come una lente, agisce effettivamente come una famiglia di\n" +"lenti, una per ogni concreto tipo di `Visitatore`." + +#: src\functional/lenses.md:250 +#, fuzzy +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 "" +"L'API `Deserializer` si basa sull'utilizzo di un insieme generico di " +"\"lenti\".\n" +"un insieme di altri tipi generici per \"osservazione\".\n" +"È un _prisma_." + +#: src\functional/lenses.md:254 +#, fuzzy +msgid "For example, consider the identity record from earlier but simplified:" +msgstr "Ad esempio, considera il record di identità precedente ma semplificato:" + +#: src\functional/lenses.md:256 +msgid "" +"```json\n" +"{ \"name\": \"Jane Doe\",\n" +" \"customer_id\": 1048576332,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:262 +#, fuzzy +msgid "" +"How would the _Serde_ library deserialize this JSON into `struct " +"CreditRecord`?" +msgstr "" +"In che modo la libreria _Serde_ deserializzerebbe questo JSON in \"struct " +"CreditRecord\"?" + +#: src\functional/lenses.md:264 +#, fuzzy +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 "" +"1. L'utente chiamerebbe una funzione di libreria per deserializzare i dati. " +"Questo sarebbe\n" +" creare un \"Deserializer\" basato sul formato JSON.\n" +"1. Sulla base dei campi nella struttura, verrebbe creato un \"Visitatore\" " +"(maggiori informazioni su\n" +" che in un attimo) che sa creare ogni tipo in un dato generico\n" +" modello necessario per rappresentarlo: `u64` e `String`.\n" +"1. Il deserializzatore effettuerebbe chiamate al \"Visitatore\" durante " +"l'analisi degli elementi.\n" +"1. Il \"Visitatore\" indicherebbe se gli elementi trovati erano attesi e, in " +"caso contrario,\n" +" genera un errore per indicare che la deserializzazione non è riuscita." + +#: src\functional/lenses.md:273 +#, fuzzy +msgid "For our very simple structure above, the expected pattern would be:" +msgstr "" +"Per la nostra struttura molto semplice sopra, il modello previsto sarebbe:" + +#: src\functional/lenses.md:275 +#, fuzzy +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 "" +"1. Visita una mappa (l'equivalente di _Serde_ a `HashMap` o il dizionario di " +"JSON).\n" +"1. Visita una chiave di stringa chiamata \"nome\".\n" +"1. Visita un valore stringa, che andrà nel campo `name`.\n" +"1. Visita una chiave stringa chiamata \"customer_id\".\n" +"1. Visita un valore stringa, che andrà nel campo `customer_id`.\n" +"1. Visita la fine della mappa." + +#: src\functional/lenses.md:282 +#, fuzzy +msgid "But what determines which \"observation\" pattern is expected?" +msgstr "Ma cosa determina quale modello di \"osservazione\" ci si aspetta?" + +#: src\functional/lenses.md:284 +#, fuzzy +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 "" +"Un linguaggio di programmazione funzionale sarebbe in grado di utilizzare il " +"currying per creare\n" +"riflesso di ogni tipo in base al tipo stesso.\n" +"Rust non lo supporta, quindi ogni singolo tipo dovrebbe averne uno proprio\n" +"codice scritto in base ai suoi campi e alle loro proprietà." + +#: src\functional/lenses.md:289 +#, fuzzy +msgid "_Serde_ solves this usability challenge with a derive macro:" +msgstr "_Serde_ risolve questa sfida di usabilità con una deriva macro:" + +#: 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 +#, fuzzy +msgid "" +"That macro simply generates an impl block causing the struct to implement a\n" +"trait called `Deserialize`." +msgstr "" +"Quella macro genera semplicemente un blocco impl che fa sì che la struct " +"implementi a\n" +"tratto chiamato \"Deserialize\"." + +#: src\functional/lenses.md:304 +#, fuzzy +msgid "It is defined this way:" +msgstr "È definito in questo modo:" + +#: 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 +#, fuzzy +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 "" +"Questa è la funzione che determina come creare la struttura stessa.\n" +"Il codice viene generato in base ai campi della struttura.\n" +"Quando viene chiamata la libreria di analisi, nel nostro esempio una " +"libreria di analisi JSON,\n" +"crea un \"Deserializer\" e chiama \"Type::deserialize\" con esso come a\n" +"parametro." + +#: src\functional/lenses.md:320 +#, fuzzy +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 "" +"Il codice `deserialize` creerà quindi un `Visitor` che avrà le sue chiamate\n" +"\"rifratta\" dal `Deserializzatore`.\n" +"Se tutto va bene, alla fine quel \"Visitatore\" costruirà un valore\n" +"corrispondente al tipo analizzato e lo restituisce." + +#: src\functional/lenses.md:325 +#, fuzzy +msgid "" +"For a complete example, see the [_Serde_ " +"documentation](https://serde.rs/deserialize-struct.html)." +msgstr "" +"Per un esempio completo, consulta la " +"[documentazione_Serde_](https://serde.rs/deserialize-struct.html)." + +#: src\functional/lenses.md:327 +#, fuzzy +msgid "To wrap up, this is the power of _Serde_:" +msgstr "Per concludere, questo è il potere di _Serde_:" + +#: src\functional/lenses.md:329 +#, fuzzy +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 "" +"1. La struttura analizzata è rappresentata da un blocco `impl` per " +"`Deserialize`\n" +"1. Il formato dei dati di input (ad es. JSON) è rappresentato da un " +"`Deserializzatore` chiamato\n" +" da \"Deserializzare\".\n" +"1. Il \"Deserializzatore\" agisce come un prisma che \"rifrange\" il " +"\"Visitatore\" simile a una lente\n" +" chiamate che effettivamente costruiscono il valore dei dati" + +#: src\functional/lenses.md:335 +#, fuzzy +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 "" +"Il risultato è che i tipi da deserializzare implementano solo il \"livello " +"superiore\" di\n" +"l'API e i formati di file devono solo implementare il \"livello " +"inferiore\".\n" +"Ogni pezzo può quindi \"funzionare semplicemente\" con il resto " +"dell'ecosistema, poiché generico\n" +"i tipi li collegheranno." + +#: src\functional/lenses.md:340 +#, fuzzy +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 "" +"Per sottolineare, l'unico motivo per cui questo modello funziona su " +"qualsiasi formato e qualsiasi tipo è\n" +"perché il tipo di output del tratto `Deserializer` **è specificato da\n" +"implementatore di `Visitor` viene passato**, piuttosto che essere legato a " +"uno specifico\n" +"tipo.\n" +"Questo non era vero nell'esempio dell'account precedente." + +#: src\functional/lenses.md:346 +#, fuzzy +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 "" +"Il sistema di tipi di ispirazione generica di Rust può avvicinarlo a questi " +"concetti e\n" +"usa il loro potere, come mostrato in questo progetto API.\n" +"Ma potrebbe anche aver bisogno di macro procedurali per creare ponti per i " +"suoi generici." + +#: src\functional/lenses.md:350 +#, fuzzy +msgid "## See Also" +msgstr "## Guarda anche" + +#: src\functional/lenses.md:352 +#, fuzzy +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 "" +"- [lens-rs crate](https://crates.io/crates/lens-rs) per obiettivi " +"predefiniti\n" +" implementazione, con un'interfaccia più pulita rispetto a questi esempi\n" +"- [serde](https://serde.rs) stesso, che rende questi concetti intuitivi per\n" +" utenti finali (ovvero definendo le strutture) senza la necessità di " +"comprendere il\n" +" dettagli\n" +"- [luminance](https://github.com/phaazon/luminance-rs) è una cassa per " +"disegnare\n" +" computer grafica che utilizza la progettazione dell'API dell'obiettivo, " +"comprese le macro procedurali per\n" +" creare prismi completi per buffer di diversi tipi di pixel che rimangono " +"generici\n" +"- [Un articolo sulle lenti in " +"Scala](https://web.archive.org/web/20221128185849/https://medium.com/zyseme-technology/functional-references-lens-and-other-optics-in- " +"scala-e5f7e2fdafe)\n" +" che è molto leggibile anche senza l'esperienza di Scala.\n" +"- [Documento: Profunctor Optics: Modular Data\n" +" " +"Accessor](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf)" + +#: src\functional/lenses.md:365 +#, fuzzy +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 "" +"[Scuola di Haskell: un piccolo tutorial per iniziare con " +"l'obiettivo](https://web.archive.org/web/20221128190041/https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of- " +"la-settimana/un-piccolo-tutorial-di-avviamento)" + +#: src\additional_resources/index.md:1 +#, fuzzy +msgid "# Additional resources" +msgstr "# Risorse addizionali" + +#: src\additional_resources/index.md:3 +#, fuzzy +msgid "A collection of complementary helpful content" +msgstr "Una raccolta di contenuti utili complementari" + +#: src\additional_resources/index.md:5 +#, fuzzy +msgid "## Talks" +msgstr "## Colloqui" + +#: src\additional_resources/index.md:7 +#, fuzzy +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 "" +"- [Modelli di design in " +"ruggine](https://www.youtube.com/watch?v=Pm_oO0N5B9k) di\n" +" Nicholas Cameron al PDRust (2016)\n" +"- [Scrivere librerie idiomatiche in " +"Rust](https://www.youtube.com/watch?v=0zOg8_B71gE)\n" +" di Pascal Hertleif al RustFest (2017)\n" +"- [Tecniche di programmazione " +"Rust](https://www.youtube.com/watch?v=vqavdUGKeb4) di\n" +" Nicholas Cameron alla LinuxConfAu (2018)" + +#: src\additional_resources/index.md:14 +#, fuzzy +msgid "## Books (Online)" +msgstr "## Libri (online)" + +#: src\additional_resources/index.md:16 +#, fuzzy +msgid "- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" +msgstr "" +"- [Le linee guida dell'API di " +"Rust](https://rust-lang.github.io/api-guidelines)" + +#: src\additional_resources/design-principles.md:1 +#, fuzzy +msgid "# Design principles" +msgstr "# Principi di progettazione" + +#: src\additional_resources/design-principles.md:3 +#, fuzzy +msgid "## A brief overview over common design principles" +msgstr "## Una breve panoramica sui principi di progettazione comuni" + +#: src\additional_resources/design-principles.md:7 +#, fuzzy +msgid "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" +msgstr "## [SOLIDO](https://en.wikipedia.org/wiki/SOLIDO)" + +#: src\additional_resources/design-principles.md:9 +#, fuzzy +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 "" +"- [Principio di responsabilità singola " +"(SRP)](https://en.wikipedia.org/wiki/Single-responsibility_principle):\n" +" Una classe dovrebbe avere una sola responsabilità, cioè solo modifiche a\n" +" una parte delle specifiche del software dovrebbe essere in grado di " +"influenzare il file\n" +" specifica della classe.\n" +"- [Principio aperto/chiuso " +"(OCP)](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle):\n" +" \"Le entità software ... dovrebbero essere aperte per l'estensione, ma " +"chiuse per\n" +" modifica.\"\n" +"- [Principio di sostituzione di Liskov " +"(LSP)](https://en.wikipedia.org/wiki/Liskov_substitution_principle):\n" +" \"Gli oggetti in un programma dovrebbero essere sostituibili con istanze " +"dei loro sottotipi\n" +" senza alterare la correttezza di quel programma.\"\n" +"- [Principio di segregazione dell'interfaccia " +"(ISP)](https://en.wikipedia.org/wiki/Interface_segregation_principle):\n" +" \"Molte interfacce specifiche del client sono migliori di una generica\n" +" interfaccia.\"\n" +"- [Principio di inversione delle dipendenze " +"(DIP)](https://en.wikipedia.org/wiki/Dependency_inversion_principle):\n" +" Si dovrebbe \"dipendere dalle astrazioni, [non] dalle concrezioni\"." + +#: src\additional_resources/design-principles.md:25 +#, fuzzy +msgid "" +"## [DRY (Don’t Repeat " +"Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" +msgstr "" +"## [DRY (Non " +"ripeterti)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" + +#: src\additional_resources/design-principles.md:27 +#, fuzzy +msgid "" +"\"Every piece of knowledge must have a single, unambiguous, authoritative\n" +"representation within a system\"" +msgstr "" +"\"Ogni conoscenza deve avere un unico, univoco, autorevole\n" +"rappresentazione all'interno di un sistema\"" + +#: src\additional_resources/design-principles.md:30 +#, fuzzy +msgid "## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" +msgstr "## [Principio KISS](https://en.wikipedia.org/wiki/KISS_principle)" + +#: 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 +#, fuzzy +msgid "## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" +msgstr "" +"## [Legge di Demetra (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" + +#: src\additional_resources/design-principles.md:38 +#, fuzzy +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 "" +"un dato oggetto dovrebbe presumere il meno possibile sulla struttura o\n" +"proprietà di qualsiasi altra cosa (compresi i suoi sottocomponenti), in " +"conformità con\n" +"il principio di \"occultamento delle informazioni\"" + +#: src\additional_resources/design-principles.md:42 +#, fuzzy +msgid "" +"## [Design by contract " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" +msgstr "" +"## [Design by contract " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" + +#: src\additional_resources/design-principles.md:44 +#, fuzzy +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 "" +"i progettisti di software dovrebbero definire un'interfaccia formale, " +"precisa e verificabile\n" +"specifiche per i componenti software, che estendono la definizione ordinaria " +"di\n" +"tipi di dati astratti con precondizioni, postcondizioni e invarianti" + +#: src\additional_resources/design-principles.md:48 +#, fuzzy +msgid "" +"## " +"[Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" +msgstr "" +"## " +"[Incapsulamento](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" + +#: src\additional_resources/design-principles.md:50 +#, fuzzy +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 "" +"raggruppamento di dati con i metodi che operano su tali dati o la " +"restrizione\n" +"di accesso diretto ad alcuni dei componenti di un oggetto. L'incapsulamento " +"è utilizzato per\n" +"nascondere i valori o lo stato di un oggetto di dati strutturati all'interno " +"di una classe, impedendo\n" +"l'accesso diretto di soggetti non autorizzati." + +#: src\additional_resources/design-principles.md:55 +#, fuzzy +msgid "" +"## " +"[Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" +msgstr "" +"## " +"[Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" + +#: src\additional_resources/design-principles.md:57 +#, fuzzy +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 "" +"“Le funzioni non dovrebbero produrre effetti collaterali astratti... solo " +"comandi\n" +"(procedure) potranno produrre effetti collaterali”. -Bertrand Mayer:\n" +"Costruzione software orientata agli oggetti" + +#: src\additional_resources/design-principles.md:61 +#, fuzzy +msgid "" +"## [Principle of least astonishment " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" +msgstr "" +"## [Principio del minimo stupore " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" + +#: src\additional_resources/design-principles.md:63 +#, fuzzy +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 "" +"un componente di un sistema dovrebbe comportarsi in un modo che la maggior " +"parte degli utenti se lo aspetta\n" +"comportarsi. Il comportamento non deve stupire o sorprendere gli utenti" + +#: src\additional_resources/design-principles.md:66 +#, fuzzy +msgid "## Linguistic-Modular-Units" +msgstr "## Unità linguistiche-modulari" + +#: src\additional_resources/design-principles.md:68 +#, fuzzy +msgid "" +"“Modules must correspond to syntactic units in the language used.” - " +"Bertrand\n" +"Meyer: Object-Oriented Software Construction" +msgstr "" +"\"I moduli devono corrispondere alle unità sintattiche nella lingua " +"utilizzata.\" - Bertrand\n" +"Meyer: costruzione di software orientato agli oggetti" + +#: src\additional_resources/design-principles.md:71 +#, fuzzy +msgid "## Self-Documentation" +msgstr "## Autodocumentazione" + +#: src\additional_resources/design-principles.md:73 +#, fuzzy +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 "" +"“Il progettista di un modulo dovrebbe sforzarsi di rendere tutte le " +"informazioni sul\n" +"modulo parte del modulo stesso.” - Bertrand Meyer: Software orientato agli " +"oggetti\n" +"Costruzione" + +#: src\additional_resources/design-principles.md:77 +#, fuzzy +msgid "## Uniform-Access" +msgstr "## Accesso uniforme" + +#: src\additional_resources/design-principles.md:79 +#, fuzzy +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 "" +"“Tutti i servizi offerti da un modulo dovrebbero essere disponibili " +"attraverso un'uniforme\n" +"notazione, che non tradisce se sono implementati tramite archiviazione o\n" +"attraverso il calcolo.” - Bertrand Meyer: Costruzione di software orientato " +"agli oggetti" + +#: src\additional_resources/design-principles.md:83 +#, fuzzy +msgid "## Single-Choice" +msgstr "## Scelta singola" + +#: src\additional_resources/design-principles.md:85 +#, fuzzy +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 "" +"“Ogni volta che un sistema software deve supportare un insieme di " +"alternative, una e sola\n" +"un modulo nel sistema dovrebbe conoscere il loro elenco esaustivo. -Bertrand " +"Mayer:\n" +"Costruzione software orientata agli oggetti" + +#: src\additional_resources/design-principles.md:89 +#, fuzzy +msgid "## Persistence-Closure" +msgstr "## Persistenza-Chiusura" + +#: src\additional_resources/design-principles.md:91 +#, fuzzy +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 "" +"“Ogni volta che un meccanismo di archiviazione immagazzina un oggetto, deve " +"immagazzinare con esso il\n" +"dipendenti di quell'oggetto. Ogni volta che un meccanismo di recupero " +"recupera a\n" +"oggetto precedentemente memorizzato, deve anche recuperare qualsiasi " +"dipendente di quell'oggetto\n" +"che non è stato ancora recuperato. - Bertrand Meyer: Software orientato agli " +"oggetti\n" +"Costruzione" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + From 56082947abb5d70b95458e3a92f3881f4f62f780 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 9 Apr 2023 03:01:02 +0200 Subject: [PATCH 169/217] Add cloud-translated es translation as a starter (#360) --- po/es.po | 10262 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 10262 insertions(+) create mode 100644 po/es.po diff --git a/po/es.po b/po/es.po new file mode 100644 index 00000000..f656dd5f --- /dev/null +++ b/po/es.po @@ -0,0 +1,10262 @@ + +msgid "" +msgstr "" +"Project-Id-Version: Rust Design Patterns\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2023-04-08 21:55+0200\n" +"Last-Translator: \n" +"Language-Team: Spanish\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src\SUMMARY.md:3 +#, fuzzy +msgid "Introduction" +msgstr "Introducción" + +#: src\SUMMARY.md:4 +#, fuzzy +msgid "Translations" +msgstr "Traducciones" + +#: src\SUMMARY.md:5 +#, fuzzy +msgid "Idioms" +msgstr "Modismos" + +#: src\SUMMARY.md:6 +#, fuzzy +msgid "Use borrowed types for arguments" +msgstr "Usar tipos prestados para argumentos" + +#: src\SUMMARY.md:7 +#, fuzzy +msgid "Concatenating Strings with format!" +msgstr "¡Concatenación de cadenas con formato!" + +#: src\SUMMARY.md:8 +#, fuzzy +msgid "Constructor" +msgstr "Constructor" + +#: src\SUMMARY.md:9 +#, fuzzy +msgid "The Default Trait" +msgstr "El rasgo predeterminado" + +#: src\SUMMARY.md:10 +#, fuzzy +msgid "Collections Are Smart Pointers" +msgstr "Las colecciones son punteros inteligentes" + +#: src\SUMMARY.md:11 +#, fuzzy +msgid "Finalisation in Destructors" +msgstr "Finalización en Destructores" + +#: src\SUMMARY.md:12 +#, fuzzy +msgid "mem::{take(_), replace(_)}" +msgstr "mem::{tomar(_), reemplazar(_)}" + +#: src\SUMMARY.md:13 +#, fuzzy +msgid "On-Stack Dynamic Dispatch" +msgstr "Despacho dinámico en pila" + +#: src\SUMMARY.md:14 src\SUMMARY.md:40 +#, fuzzy +msgid "Foreign function interface (FFI)" +msgstr "Interfaz de función externa (FFI)" + +#: src\SUMMARY.md:15 +#, fuzzy +msgid "Idiomatic Errors" +msgstr "Errores idiomáticos" + +#: src\SUMMARY.md:16 +#, fuzzy +msgid "Accepting Strings" +msgstr "Aceptar cadenas" + +#: src\SUMMARY.md:17 +#, fuzzy +msgid "Passing Strings" +msgstr "Pasar cuerdas" + +#: src\SUMMARY.md:18 +#, fuzzy +msgid "Iterating over an Option" +msgstr "Iterando sobre una opción" + +#: src\SUMMARY.md:19 +#, fuzzy +msgid "Pass Variables to Closure" +msgstr "Pasar variables al cierre" + +#: src\SUMMARY.md:20 +#, fuzzy +msgid "Privacy For Extensibility" +msgstr "Privacidad para extensibilidad" + +#: src\SUMMARY.md:21 +#, fuzzy +msgid "Easy doc initialization" +msgstr "Fácil inicialización de documentos" + +#: src\SUMMARY.md:22 +#, fuzzy +msgid "Temporary mutability" +msgstr "Mutabilidad temporal" + +#: src\SUMMARY.md:23 +#, fuzzy +msgid "Return consumed arg on error" +msgstr "Devolver argumento consumido en caso de error" + +#: src\SUMMARY.md:25 +#, fuzzy +msgid "Design Patterns" +msgstr "Patrones de diseño" + +#: src\SUMMARY.md:26 +#, fuzzy +msgid "Behavioural" +msgstr "conductual" + +#: src\SUMMARY.md:27 +#, fuzzy +msgid "Command" +msgstr "Dominio" + +#: src\SUMMARY.md:28 +#, fuzzy +msgid "Interpreter" +msgstr "Intérprete" + +#: src\SUMMARY.md:29 +#, fuzzy +msgid "Newtype" +msgstr "Nuevo tipo" + +#: src\SUMMARY.md:30 +#, fuzzy +msgid "RAII Guards" +msgstr "Guardias RAII" + +#: src\SUMMARY.md:31 +#, fuzzy +msgid "Strategy" +msgstr "Estrategia" + +#: src\SUMMARY.md:32 +#, fuzzy +msgid "Visitor" +msgstr "Visitante" + +#: src\SUMMARY.md:33 +#, fuzzy +msgid "Creational" +msgstr "Creacional" + +#: src\SUMMARY.md:34 +#, fuzzy +msgid "Builder" +msgstr "Constructor" + +#: src\SUMMARY.md:35 +#, fuzzy +msgid "Fold" +msgstr "Doblar" + +#: src\SUMMARY.md:36 +#, fuzzy +msgid "Structural" +msgstr "Estructural" + +#: src\SUMMARY.md:37 +#, fuzzy +msgid "Compose Structs" +msgstr "Componer estructuras" + +#: src\SUMMARY.md:38 +#, fuzzy +msgid "Prefer Small Crates" +msgstr "Preferir cajas pequeñas" + +#: src\SUMMARY.md:39 +#, fuzzy +msgid "Contain unsafety in small modules" +msgstr "Contener la inseguridad en pequeños módulos" + +#: src\SUMMARY.md:41 +#, fuzzy +msgid "Object-Based APIs" +msgstr "API basadas en objetos" + +#: src\SUMMARY.md:42 +#, fuzzy +msgid "Type Consolidation into Wrappers" +msgstr "Escriba la consolidación en contenedores" + +#: src\SUMMARY.md:44 +#, fuzzy +msgid "Anti-patterns" +msgstr "Anti-patrones" + +#: src\SUMMARY.md:45 +#, fuzzy +msgid "Clone to satisfy the borrow checker" +msgstr "Clonar para satisfacer el verificador de préstamo" + +#: src\SUMMARY.md:46 +#, fuzzy +msgid "#[deny(warnings)]" +msgstr "#[negar(advertencias)]" + +#: src\SUMMARY.md:47 +#, fuzzy +msgid "Deref Polymorphism" +msgstr "Polimorfismo Deref" + +#: src\SUMMARY.md:49 +#, fuzzy +msgid "Functional Programming" +msgstr "Programación funcional" + +#: src\SUMMARY.md:50 +#, fuzzy +msgid "Programming paradigms" +msgstr "Paradigmas de programación" + +#: src\SUMMARY.md:51 +#, fuzzy +msgid "Generics as Type Classes" +msgstr "Genéricos como clases de tipos" + +#: src\SUMMARY.md:52 +#, fuzzy +msgid "Lenses and Prisms" +msgstr "lentes y prismas" + +#: src\SUMMARY.md:54 +#, fuzzy +msgid "Additional Resources" +msgstr "Recursos adicionales" + +#: src\SUMMARY.md:55 +#, fuzzy +msgid "Design principles" +msgstr "Criterios de diseño" + +#: src\intro.md:1 +#, fuzzy +msgid "# Introduction" +msgstr "# Introducción" + +#: src\intro.md:3 +#, fuzzy +msgid "## Participation" +msgstr "## Participación" + +#: src\intro.md:5 +#, fuzzy +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 "" +"Si está interesado en contribuir a este libro, consulte el\n" +"[directrices de " +"contribución](https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md)." + +#: src\intro.md:8 +#, fuzzy +msgid "## Design patterns" +msgstr "## Patrones de diseño" + +#: src\intro.md:10 +#, fuzzy +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 "" +"En el desarrollo de software, a menudo nos encontramos con problemas que " +"comparten\n" +"similitudes independientemente del entorno en el que aparecen. Aunque el\n" +"detalles de implementación son cruciales para resolver la tarea en cuestión, " +"podemos\n" +"abstraerse de estas particularidades para encontrar las prácticas comunes " +"que\n" +"son de aplicación genérica." + +#: src\intro.md:16 +#, fuzzy +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 "" +"Los patrones de diseño son una colección de soluciones reutilizables y " +"probadas para\n" +"problemas recurrentes en ingeniería. Hacen que nuestro software sea más " +"modular,\n" +"mantenible y extensible. Además, estos patrones proporcionan un común\n" +"lenguaje para desarrolladores, lo que los convierte en una excelente " +"herramienta para\n" +"comunicación en la resolución de problemas en equipo." + +#: src\intro.md:22 src\patterns/index.md:14 +#, fuzzy +msgid "## Design patterns in Rust" +msgstr "## Patrones de diseño en Rust" + +#: src\intro.md:24 +#, fuzzy +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 "" +"Rust no está orientado a objetos, y la combinación de todas sus " +"características,\n" +"tales como elementos funcionales, un sistema de tipo fuerte y el verificador " +"de préstamo,\n" +"lo hace único.\n" +"Debido a esto, los patrones de diseño de Rust varían con respecto a otros\n" +"lenguajes de programación tradicionales orientados a objetos.\n" +"Por eso decidimos escribir este libro. ¡Esperamos que disfrutes leyéndolo!\n" +"El libro se divide en tres capítulos principales:" + +#: src\intro.md:32 +#, fuzzy +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 "" +"- [Expresiones idiomáticas](./idioms/index.md): pautas a seguir al " +"codificar.\n" +" Son las normas sociales de la comunidad.\n" +" Debe romperlos solo si tiene una buena razón para ello.\n" +"- [Patrones de diseño] (./patrones/index.md): métodos para resolver " +"problemas comunes\n" +" al codificar.\n" +"- [Anti-patterns](./anti_patterns/index.md): métodos para resolver problemas " +"comunes\n" +" al codificar.\n" +" Sin embargo, mientras que los patrones de diseño nos dan beneficios,\n" +" los antipatrones crean más problemas." + +#: src\translations.md:1 +#, fuzzy +msgid "# Translations" +msgstr "# Traducciones" + +#: src\translations.md:3 +#, fuzzy +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 "" +"Estamos utilizando " +"[mdbook-i18n-helper](https://github.com/google/mdbook-i18n-helpers).\n" +"Lea cómo _agregar_ y _actualizar_ traducciones en [su " +"repositorio](https://github.com/google/mdbook-i18n-helpers#creating-and-updating-translations)" + +#: src\translations.md:6 +#, fuzzy +msgid "## External translations" +msgstr "## Traducciones externas" + +#: src\translations.md:8 +#, fuzzy +msgid "- [简体中文](https://fomalhauthmj.github.io/patterns/)" +msgstr "- [简体中文](https://fomalhauthmj.github.io/patterns/)" + +#: src\translations.md:10 +#, fuzzy +msgid "" +"If you want to add a translation, please open an issue in the\n" +"[main repository](https://github.com/rust-unofficial/patterns)." +msgstr "" +"Si desea agregar una traducción, abra un problema en el\n" +"[repositorio principal](https://github.com/rust-unofficial/patterns)." + +#: src\idioms/index.md:1 +#, fuzzy +msgid "# Idioms" +msgstr "# Modismos" + +#: src\idioms/index.md:3 +#, fuzzy +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 "" +"[Los modismos] (https://en.wikipedia.org/wiki/Programming_idiom) se usan " +"comúnmente\n" +"estilos, pautas y patrones acordados en gran medida por una comunidad.\n" +"Escribir código idiomático permite que otros desarrolladores entiendan mejor " +"qué es\n" +"sucediendo." + +#: src\idioms/index.md:8 +#, fuzzy +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 "" +"Después de todo, a la computadora solo le importa el código de máquina que " +"se genera.\n" +"por el compilador.\n" +"En cambio, el código fuente es principalmente beneficioso para el " +"desarrollador.\n" +"Entonces, ya que tenemos esta capa de abstracción, ¿por qué no hacerla más " +"legible?" + +#: 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 +#, fuzzy +msgid "> Code is there for humans, not computers, to understand." +msgstr "" +"> El código está ahí para que lo entiendan los humanos, no las computadoras." + +#: src\idioms/coercion-arguments.md:1 +#, fuzzy +msgid "# Use borrowed types for arguments" +msgstr "# Usar tipos prestados para argumentos" + +#: 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 +#, fuzzy +msgid "## Description" +msgstr "## Descripción" + +#: src\idioms/coercion-arguments.md:5 +#, fuzzy +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 "" +"El uso de un objetivo de coerción de desref puede aumentar la flexibilidad " +"de su código\n" +"cuando está decidiendo qué tipo de argumento usar para un argumento de " +"función.\n" +"De esta forma, la función aceptará más tipos de entrada." + +#: src\idioms/coercion-arguments.md:9 +#, fuzzy +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 "" +"Esto no se limita a los tipos de puntero gordo o rebanable.\n" +"De hecho, siempre debe preferir usar el **tipo prestado** en lugar de\n" +"**tomando prestado el tipo propio**.\n" +"Como `&str` sobre `&String`, `&[T]` sobre `&Vec`, o `&T` sobre `&Box`." + +#: src\idioms/coercion-arguments.md:14 +#, fuzzy +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 "" +"Usando tipos prestados puede evitar capas de direccionamiento indirecto para " +"esas instancias\n" +"donde el tipo propio ya proporciona una capa de direccionamiento indirecto. " +"Por ejemplo, un\n" +"`String` tiene una capa de direccionamiento indirecto, por lo que `&String` " +"tendrá dos capas de\n" +"indirección Podemos evitar esto usando `&str` en su lugar, y dejando que " +"`&String`\n" +"coaccionar a `&str` cada vez que se invoca la función." + +#: 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 +#, fuzzy +msgid "## Example" +msgstr "## Ejemplo" + +#: src\idioms/coercion-arguments.md:22 +#, fuzzy +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 "" +"Para este ejemplo, ilustraremos algunas diferencias al usar `&String` como\n" +"argumento de función versus usar `&str`, pero las ideas se aplican también " +"al uso\n" +"`&Vec` versus usar `&[T]` o usar `&Box` versus `&T`." + +#: src\idioms/coercion-arguments.md:26 +#, fuzzy +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 "" +"Considere un ejemplo donde deseamos determinar si una palabra contiene tres\n" +"vocales consecutivas. No necesitamos ser dueños de la cadena para determinar " +"esto, así que\n" +"tomará una referencia." + +#: src\idioms/coercion-arguments.md:30 +#, fuzzy +msgid "The code might look something like this:" +msgstr "El código podría ser algo como esto:" + +#: 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 +#, fuzzy +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 "" +"Esto funciona bien porque estamos pasando un tipo `&String` como parámetro.\n" +"Si eliminamos los comentarios de las dos últimas líneas, el ejemplo fallará. " +"Este\n" +"es porque un tipo `&str` no forzará a un tipo `&String`. podemos arreglar " +"esto\n" +"simplemente modificando el tipo de nuestro argumento." + +#: src\idioms/coercion-arguments.md:67 +#, fuzzy +msgid "For instance, if we change our function declaration to:" +msgstr "Por ejemplo, si cambiamos nuestra declaración de función a:" + +#: src\idioms/coercion-arguments.md:69 +msgid "" +"```rust, ignore\n" +"fn three_vowels(word: &str) -> bool {\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:73 +#, fuzzy +msgid "then both versions will compile and print the same output." +msgstr "entonces ambas versiones compilarán e imprimirán el mismo resultado." + +#: src\idioms/coercion-arguments.md:75 +msgid "" +"```bash\n" +"Ferris: false\n" +"Curious: true\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:80 +#, fuzzy +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 "" +"Pero espera, ¡eso no es todo! Hay más en esta historia.\n" +"Es probable que te digas a ti mismo: eso no importa, nunca seré\n" +"usando `&'static str` como entrada de todos modos (como hicimos cuando " +"usamos `\"Ferris\"`).\n" +"Incluso ignorando este ejemplo especial, aún puede encontrar que usar " +"`&str`\n" +"darle más flexibilidad que usar un `&String`." + +#: src\idioms/coercion-arguments.md:86 +#, fuzzy +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 "" +"Ahora tomemos un ejemplo en el que alguien nos da una oración y queremos\n" +"determinar si alguna de las palabras de la oración contiene tres vocales " +"consecutivas.\n" +"Probablemente deberíamos hacer uso de la función que ya hemos definido y " +"simplemente\n" +"Introduzca cada palabra de la oración." + +#: src\idioms/coercion-arguments.md:91 +#, fuzzy +msgid "An example of this could look like this:" +msgstr "Un ejemplo de esto podría verse así:" + +#: 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 +#, fuzzy +msgid "" +"Running this example using our function declared with an argument type " +"`&str`\n" +"will yield" +msgstr "" +"Ejecutando este ejemplo usando nuestra función declarada con un tipo de " +"argumento `&str`\n" +"rendirá" + +#: src\idioms/coercion-arguments.md:124 +msgid "" +"```bash\n" +"curious has three consecutive vowels!\n" +"```" +msgstr "" + +#: src\idioms/coercion-arguments.md:128 +#, fuzzy +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 "" +"Sin embargo, este ejemplo no se ejecutará cuando nuestra función se declare " +"con un\n" +"tipo de argumento `&String`. Esto se debe a que los segmentos de cadena son " +"un `&str` y no un\n" +"`&String` que requeriría convertir una asignación a `&String` que\n" +"no es implícito, mientras que convertir de `String` a `&str` es económico e " +"implícito." + +#: 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 +#, fuzzy +msgid "## See also" +msgstr "## Ver también" + +#: src\idioms/coercion-arguments.md:135 +#, fuzzy +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 "" +"- [Referencia del lenguaje Rust sobre coerciones de " +"tipos](https://doc.rust-lang.org/reference/type-coercions.html)\n" +"- Para obtener más información sobre cómo manejar `String` y `&str`, " +"consulte\n" +" [esta serie de blogs " +"(2015)](https://web.archive.org/web/20201112023149/https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html " +")\n" +" por Herman J. Radtke III" + +#: src\idioms/concat-format.md:1 +#, fuzzy +msgid "# Concatenating strings with `format!`" +msgstr "# Concatenar cadenas con `formato!`" + +#: src\idioms/concat-format.md:5 +#, fuzzy +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 "" +"Es posible construir cadenas usando los métodos `push` y `push_str` en un\n" +"`String` mutable, o usando su operador `+`. Sin embargo, a menudo es más\n" +"conveniente usar `formato!`, especialmente donde hay una mezcla de literal " +"y\n" +"cadenas no literales." + +#: 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 +#, fuzzy +msgid "## Advantages" +msgstr "## Ventajas" + +#: src\idioms/concat-format.md:27 +#, fuzzy +msgid "" +"Using `format!` is usually the most succinct and readable way to combine " +"strings." +msgstr "" +"Usar `format!` suele ser la forma más sucinta y legible de combinar cadenas." + +#: 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 +#, fuzzy +msgid "## Disadvantages" +msgstr "## Desventajas" + +#: src\idioms/concat-format.md:31 +#, fuzzy +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 "" +"Por lo general, no es la forma más eficiente de combinar cadenas: una serie " +"de `push`\n" +"operaciones en una cadena mutable suele ser la más eficiente (especialmente " +"si el\n" +"cadena se ha preasignado al tamaño esperado)." + +#: src\idioms/ctor.md:1 +#, fuzzy +msgid "# Constructors\r" +msgstr "# Constructores\r" + +#: src\idioms/ctor.md:3 src\idioms/rustdoc-init.md:3 +#, fuzzy +msgid "## Description\r" +msgstr "## Descripción\r" + +#: src\idioms/ctor.md:5 +#, fuzzy +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 "" +"Rust no tiene constructores como una construcción de lenguaje. En cambio, " +"el\r\n" +"la convención es usar una [función asociada][función asociada] `nueva` para " +"crear un objeto:" + +#: 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 +#, fuzzy +msgid "## Default Constructors\r" +msgstr "## Constructores predeterminados\r" + +#: src\idioms/ctor.md:37 +#, fuzzy +msgid "" +"Rust supports default constructors with the [`Default`][std-default] trait:" +msgstr "" +"Rust admite constructores predeterminados con el rasgo " +"[`Default`][std-default]:" + +#: 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 +#, fuzzy +msgid "" +"`Default` can also be derived if all types of all fields implement " +"`Default`,\r\n" +"like they do with `Second`:" +msgstr "" +"`Predeterminado` también se puede derivar si todos los tipos de todos los " +"campos implementan `Predeterminado`,\r\n" +"como lo hacen con `Second`:" + +#: 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 +#, fuzzy +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 "" +"**Nota:** Es común y se espera que los tipos implementen ambos\r\n" +"'Predeterminado' y un constructor 'nuevo' vacío. `nuevo` es el " +"constructor\r\n" +"convención en Rust, y los usuarios esperan que exista, por lo que si es\r\n" +"razonable que el constructor básico no tome argumentos, entonces\r\n" +"debería, incluso si es funcionalmente idéntico al predeterminado." + +#: src\idioms/ctor.md:97 +#, fuzzy +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 "" +"**Sugerencia:** La ventaja de implementar o derivar `Default` es que su " +"tipo\r\n" +"ahora se puede usar donde se requiere una implementación 'Predeterminada', " +"más prominentemente,\r\n" +"cualquiera de las funciones [`*or_default` en la biblioteca " +"estándar][std-or-default]." + +#: src\idioms/ctor.md:101 +#, fuzzy +msgid "## See also\r" +msgstr "## Ver también\r" + +#: src\idioms/ctor.md:103 +#, fuzzy +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 "" +"- El [modismo predeterminado](default.md) para una descripción más detallada " +"del\r\n" +" Rasgo 'predeterminado'.\r\n" +"\r\n" +"- El [patrón del constructor] (../patterns/creational/builder.md) para " +"construir\r\n" +" objetos donde hay múltiples configuraciones.\r\n" +"\r\n" +"- [Directrices API/C-COMMON-TRAITS][Directrices API/C-COMMON-TRAITS] para\r\n" +" implementando ambos, `Predeterminado` y `nuevo`.\r\n" +"\r" + +#: src\idioms/default.md:1 +#, fuzzy +msgid "# The `Default` Trait" +msgstr "# El rasgo `Por defecto`" + +#: 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 +#, fuzzy +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 "" +"No solo implementan contenedores de un elemento como `Cow`, `Box` o `Arc`\n" +"'Predeterminado' para los tipos 'Predeterminados' contenidos, uno puede " +"automáticamente\n" +"`#[derive(Default)]` para estructuras cuyos campos lo implementan, así que " +"cuanto más\n" +"tipos implementan `Default`, más útil se vuelve." + +#: src\idioms/default.md:16 +#, fuzzy +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 "" +"Por otro lado, los constructores pueden tomar múltiples argumentos, mientras " +"que los\n" +"El método `default()` no lo hace. Incluso puede haber múltiples " +"constructores con\n" +"nombres diferentes, pero solo puede haber una implementación " +"`Predeterminada` por tipo." + +#: 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 +#, fuzzy +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 "" +"- El lenguaje [constructor] es otra forma de generar instancias que pueden o " +"pueden\n" +" no ser \"predeterminado\"\n" +"- La documentación [`Default`] (desplácese hacia abajo para ver la lista de " +"implementadores)\n" +"- [`Opción::unwrap_or_default()`]\n" +"- [`derivar(nuevo)`]" + +#: src\idioms/deref.md:1 +#, fuzzy +msgid "# Collections are smart pointers" +msgstr "# Las colecciones son punteros inteligentes" + +#: src\idioms/deref.md:5 +#, fuzzy +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 "" +"Utilice [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)\n" +"rasgo para tratar las colecciones como punteros inteligentes, ofreciendo " +"propiedad\n" +"y vistas prestadas de datos." + +#: 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 +#, fuzzy +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 "" +"Un `Vec` es una colección propietaria de `T`s, mientras que un segmento " +"(`&[T]`) es un préstamo\n" +"colección de `T`s. La implementación de `Deref` para `Vec` permite la " +"desreferenciación implícita\n" +"de `&Vec` a `&[T]` e incluye la relación en la eliminación automática de " +"referencias\n" +"búsquedas. La mayoría de los métodos que podría esperar que se implementen " +"para `Vec`s son en su lugar\n" +"implementado para rebanadas." + +#: src\idioms/deref.md:34 +#, fuzzy +msgid "Also `String` and `&str` have a similar relation." +msgstr "También `String` y `&str` tienen una relación similar." + +#: 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 +#, fuzzy +msgid "## Motivation" +msgstr "## Motivación" + +#: src\idioms/deref.md:38 +#, fuzzy +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 "" +"La propiedad y el préstamo son aspectos clave del lenguaje Rust. Estructuras " +"de datos\n" +"debe tener en cuenta esta semántica correctamente para dar a un buen " +"usuario\n" +"experiencia. Al implementar una estructura de datos que posee sus datos, " +"ofrecer una\n" +"La vista prestada de esos datos permite API más flexibles." + +#: src\idioms/deref.md:45 +#, fuzzy +msgid "" +"Most methods can be implemented only for the borrowed view, they are then\n" +"implicitly available for the owning view." +msgstr "" +"La mayoría de los métodos se pueden implementar solo para la vista prestada, " +"luego se\n" +"implícitamente disponible para la vista propietaria." + +#: src\idioms/deref.md:48 +#, fuzzy +msgid "Gives clients a choice between borrowing or taking ownership of data." +msgstr "" +"Brinda a los clientes la opción de tomar prestados o tomar posesión de los " +"datos." + +#: src\idioms/deref.md:52 +#, fuzzy +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 "" +"No se tienen en cuenta los métodos y características que solo están " +"disponibles a través de la desreferenciación.\n" +"cuando se verifican los límites, por lo que la programación genérica con " +"estructuras de datos usa esto\n" +"El patrón puede volverse complejo (ver los rasgos `Borrow` y `AsRef`, etc.)." + +#: 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 +#, fuzzy +msgid "## Discussion" +msgstr "## Discusión" + +#: src\idioms/deref.md:58 +#, fuzzy +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 "" +"Los punteros inteligentes y las colecciones son análogos: un puntero " +"inteligente apunta a un solo\n" +"objeto, mientras que una colección apunta a muchos objetos. Desde el punto " +"de vista de\n" +"el sistema de tipos, hay poca diferencia entre los dos. Una colección posee\n" +"sus datos si la única forma de acceder a cada dato es a través de la " +"recopilación y el\n" +"recogida es responsable de la eliminación de los datos (incluso en los casos " +"de compartir\n" +"propiedad, algún tipo de vista prestada puede ser apropiado). Si una " +"colección posee\n" +"sus datos, por lo general es útil proporcionar una vista de los datos como " +"prestados para que\n" +"puede ser referenciado varias veces." + +#: src\idioms/deref.md:67 +#, fuzzy +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 "" +"La mayoría de los punteros inteligentes (por ejemplo, `Foo`) implementan " +"`Deref`. Sin embargo,\n" +"las colecciones por lo general dejarán de hacer referencia a un tipo " +"personalizado. `[T]` y `str` tienen algunos\n" +"soporte de idioma, pero en el caso general, esto no es necesario. `Foo` " +"puede\n" +"implementar `Deref>` donde `Bar` es un tipo de tamaño dinámico " +"y\n" +"`&Bar` es una vista prestada de los datos en `Foo`." + +#: src\idioms/deref.md:73 +#, fuzzy +msgid "" +"Commonly, ordered collections will implement `Index` for `Range`s to " +"provide\n" +"slicing syntax. The target will be the borrowed view." +msgstr "" +"Comúnmente, las colecciones ordenadas implementarán `Index` para `Range`s " +"para proporcionar\n" +"sintaxis de corte. El objetivo será la vista prestada." + +#: src\idioms/deref.md:78 +#, fuzzy +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 "" +"- [Antipatrón de polimorfismo de deref](../anti_patterns/deref.md).\n" +"- [Documentación para el rasgo " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\idioms/dtor-finally.md:1 +#, fuzzy +msgid "# Finalisation in destructors" +msgstr "# Finalización en destructores" + +#: src\idioms/dtor-finally.md:5 +#, fuzzy +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 "" +"Rust no proporciona el equivalente a los bloques `finally` - código que " +"será\n" +"se ejecuta sin importar cómo se sale de una función. En cambio, el " +"destructor de un objeto puede\n" +"usarse para ejecutar código que debe ejecutarse antes de salir." + +#: 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 +#, fuzzy +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 "" +"Si una función tiene varios puntos de retorno, la ejecución del código al " +"salir se vuelve\n" +"difícil y repetitivo (y por lo tanto propenso a errores). Este es " +"especialmente el caso donde\n" +"el retorno es implícito debido a una macro. Un caso común es el operador `?` " +"que\n" +"devuelve si el resultado es `Err`, pero continúa si es `Ok`. `?` se utiliza " +"como\n" +"un mecanismo de manejo de excepciones, pero a diferencia de Java (que tiene " +"`finally`), hay\n" +"no hay forma de programar el código para que se ejecute tanto en casos " +"normales como excepcionales.\n" +"El pánico también hará que salga de una función antes de tiempo." + +#: src\idioms/dtor-finally.md:44 +#, fuzzy +msgid "" +"Code in destructors will (nearly) always be run - copes with panics, early\n" +"returns, etc." +msgstr "" +"El código en los destructores (casi) siempre se ejecutará: hace frente a " +"pánicos, temprano\n" +"devoluciones, etc" + +#: src\idioms/dtor-finally.md:49 +#, fuzzy +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 "" +"No se garantiza que los destructores funcionen. Por ejemplo, si hay un\n" +"bucle infinito en una función o si la ejecución de una función falla antes " +"de salir.\n" +"Los destructores tampoco se ejecutan en caso de pánico en un país que ya " +"está en pánico.\n" +"hilo. Por lo tanto, no se puede confiar en los destructores como " +"finalizadores donde es\n" +"absolutamente esencial que ocurra la finalización." + +#: src\idioms/dtor-finally.md:55 +#, fuzzy +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 "" +"Este patrón introduce un código implícito difícil de notar. Lectura de una " +"función\n" +"no da una indicación clara de los destructores que se ejecutarán en la " +"salida. esto puede hacer\n" +"depuración complicada." + +#: src\idioms/dtor-finally.md:59 +#, fuzzy +msgid "" +"Requiring an object and `Drop` impl just for finalisation is heavy on " +"boilerplate." +msgstr "" +"Requerir un objeto y el impl `Drop` solo para la finalización es pesado en " +"el modelo." + +#: src\idioms/dtor-finally.md:63 +#, fuzzy +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 "" +"Hay cierta sutileza sobre cómo almacenar exactamente el objeto utilizado " +"como\n" +"finalizador Debe mantenerse vivo hasta el final de la función y luego debe " +"ser\n" +"destruido. El objeto siempre debe ser un valor o un puntero de propiedad " +"única (por ejemplo,\n" +"`Cuadro`). Si se usa un puntero compartido (como `Rc`), entonces el " +"finalizador puede\n" +"mantenerse vivo más allá del tiempo de vida de la función. Por razones " +"similares, el\n" +"el finalizador no debe moverse ni devolverse." + +#: src\idioms/dtor-finally.md:70 +#, fuzzy +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 "" +"El finalizador debe asignarse a una variable, de lo contrario, se destruirá\n" +"inmediatamente, en lugar de cuando se sale del alcance. El nombre de la " +"variable debe comenzar\n" +"con `_` si la variable solo se usa como finalizador, de lo contrario, el " +"compilador\n" +"advertirá que el finalizador nunca se utiliza. Sin embargo, no llame a la " +"variable\n" +"`_` sin sufijo - en ese caso será destruido inmediatamente." + +#: src\idioms/dtor-finally.md:76 +#, fuzzy +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 "" +"En Rust, los destructores se ejecutan cuando un objeto queda fuera del " +"alcance. Esto pasa\n" +"ya sea que lleguemos al final del bloque, que haya un regreso anticipado o " +"que el programa\n" +"entra en pánico Cuando entra en pánico, Rust desenrolla la pila ejecutando " +"destructores para cada\n" +"objeto en cada marco de pila. Entonces, se llama a los destructores incluso " +"si ocurre el pánico.\n" +"en una función que se está llamando." + +#: src\idioms/dtor-finally.md:82 +#, fuzzy +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 "" +"Si un destructor entra en pánico mientras se desenrolla, no hay una buena " +"acción que tomar, por lo que Rust\n" +"aborta el subproceso inmediatamente, sin ejecutar más destructores. Esto " +"significa\n" +"que los destructores no están absolutamente garantizados para funcionar. " +"También significa que usted\n" +"debe tener especial cuidado en sus destructores para no entrar en pánico, ya " +"que podría salir\n" +"recursos en un estado inesperado." + +#: src\idioms/dtor-finally.md:90 +#, fuzzy +msgid "[RAII guards](../patterns/behavioural/RAII.md)." +msgstr "[Guardias RAII](../patrones/comportamiento/RAII.md)." + +#: src\idioms/mem-replace.md:1 +#, fuzzy +msgid "# `mem::{take(_), replace(_)}` to keep owned values in changed enums" +msgstr "" +"# `mem::{take(_), replace(_)}` para mantener los valores propios en las " +"enumeraciones modificadas" + +#: src\idioms/mem-replace.md:5 +#, fuzzy +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 "" +"Digamos que tenemos un `&mut MyEnum` que tiene (al menos) dos variantes,\n" +"`A { nombre: Cadena, x: u8 }` y `B { nombre: Cadena }`. Ahora queremos " +"cambiar\n" +"`MyEnum::A` a `B` si `x` es cero, manteniendo `MyEnum::B` intacto." + +#: src\idioms/mem-replace.md:9 +#, fuzzy +msgid "We can do this without cloning the `name`." +msgstr "Podemos hacer esto sin clonar el `nombre`." + +#: 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 +#, fuzzy +msgid "This also works with more variants:" +msgstr "Esto también funciona con más variantes:" + +#: 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 +#, fuzzy +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 "" +"Al trabajar con enumeraciones, es posible que deseemos cambiar un valor de " +"enumeración en su lugar, tal vez\n" +"a otra variante. Esto generalmente se hace en dos fases para mantener el " +"préstamo\n" +"corrector feliz. En la primera fase, observamos el valor existente y " +"miramos\n" +"sus partes para decidir qué hacer a continuación. En la segunda fase podemos " +"condicionalmente\n" +"cambiar el valor (como en el ejemplo anterior)." + +#: src\idioms/mem-replace.md:65 +#, fuzzy +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 "" +"El verificador de préstamos no nos permitirá sacar el `nombre` de la " +"enumeración (porque\n" +"_algo_ debe estar allí.) Podríamos, por supuesto, el nombre `.clone()` y " +"poner el clon\n" +"en nuestro `MyEnum::B`, pero eso sería una instancia del antipatrón [Clonar " +"para satisfacer el comprobador de " +"préstamos](../anti_patterns/borrow_clone.md). De todos modos, nosotros\n" +"puede evitar la asignación adicional cambiando `e` con solo un préstamo " +"mutable." + +#: src\idioms/mem-replace.md:70 +#, fuzzy +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 "" +"`mem::take` nos permite intercambiar el valor, reemplazándolo con su valor " +"predeterminado,\n" +"y devolviendo el valor anterior. Para `String`, el valor predeterminado es " +"un vacío\n" +"`String`, que no es necesario asignar. Como resultado, obtenemos el " +"original.\n" +"`nombre` _como valor propio_. Luego podemos envolver esto en otra " +"enumeración." + +#: src\idioms/mem-replace.md:75 +#, fuzzy +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 "" +"**NOTA:** `mem::replace` es muy similar, pero nos permite especificar qué\n" +"reemplace el valor con. Un equivalente a nuestra línea `mem::take` sería\n" +"`mem::replace(nombre, Cadena::nuevo())`." + +#: src\idioms/mem-replace.md:79 +#, fuzzy +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 "" +"Tenga en cuenta, sin embargo, que si estamos usando una `Opción` y queremos " +"reemplazar su\n" +"valor con `Ninguno`, el método `take()` de `Option` proporciona un método " +"más corto y\n" +"alternativa más idiomática." + +#: src\idioms/mem-replace.md:85 +#, fuzzy +msgid "" +"Look ma, no allocation! Also you may feel like Indiana Jones while doing it." +msgstr "" +"¡Mira mamá, no hay asignación! También puedes sentirte como Indiana Jones " +"mientras lo haces." + +#: src\idioms/mem-replace.md:89 +#, fuzzy +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 "" +"Esto se pone un poco prolijo. Hacerlo mal repetidamente te hará odiar el\n" +"prestador de cheques. El compilador puede fallar al optimizar el almacén " +"doble,\n" +"lo que resulta en un rendimiento reducido en comparación con lo que haría en " +"un entorno inseguro\n" +"idiomas" + +#: src\idioms/mem-replace.md:94 +#, fuzzy +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 "" +"Además, el tipo que está tomando debe implementar el [rasgo " +"`Predeterminado`] (./default.md). Sin embargo, si el tipo con el que está " +"trabajando no\n" +"implementar esto, en su lugar puede usar `mem::replace`." + +#: src\idioms/mem-replace.md:99 +#, fuzzy +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 "" +"Este patrón solo es de interés en Rust. En los idiomas de GC, tomarías la\n" +"referencia al valor por defecto (y el GC haría un seguimiento de las " +"referencias), y en\n" +"otros lenguajes de bajo nivel como C simplemente haría un alias del puntero " +"y arreglaría las cosas\n" +"más tarde." + +#: src\idioms/mem-replace.md:104 +#, fuzzy +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 "" +"Sin embargo, en Rust, tenemos que trabajar un poco más para hacer esto. Un " +"valor propio\n" +"Es posible que solo tenga un propietario, por lo que para sacarlo, debemos " +"volver a colocar algo:\n" +"como Indiana Jones, reemplazando el artefacto con una bolsa de arena." + +#: src\idioms/mem-replace.md:110 +#, fuzzy +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 "" +"Esto elimina el [Clonar para satisfacer el comprobador de " +"préstamo](../anti_patterns/borrow_clone.md)\n" +"anti-patrón en un caso específico." + +#: src\idioms/on-stack-dyn-dispatch.md:1 +#, fuzzy +msgid "# On-Stack Dynamic Dispatch" +msgstr "# Envío dinámico en la pila" + +#: src\idioms/on-stack-dyn-dispatch.md:5 +#, fuzzy +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 "" +"Podemos despachar dinámicamente sobre múltiples valores, sin embargo, para " +"hacerlo, necesitamos\n" +"para declarar múltiples variables para vincular objetos de diferente tipo. " +"para extender el\n" +"vida útil según sea necesario, podemos usar la inicialización condicional " +"diferida, como se ve\n" +"abajo:" + +#: 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 +#, fuzzy +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 "" +"Rust monomorfiza el código por defecto. Esto significa que una copia del " +"código será\n" +"generado para cada tipo con el que se utiliza y optimizado de forma " +"independiente. Mientras esto\n" +"permite un código muy rápido en la ruta activa, también infla el código en " +"algunos lugares\n" +"donde el rendimiento no es esencial, lo que cuesta tiempo de compilación y " +"caché\n" +"uso." + +#: src\idioms/on-stack-dyn-dispatch.md:45 +#, fuzzy +msgid "" +"Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly " +"ask\n" +"for it." +msgstr "" +"Afortunadamente, Rust nos permite usar el envío dinámico, pero tenemos que " +"preguntar explícitamente\n" +"para ello." + +#: src\idioms/on-stack-dyn-dispatch.md:50 +#, fuzzy +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 "" +"No necesitamos asignar nada en el montón. Tampoco necesitamos\n" +"inicializar algo que no usaremos más tarde, ni necesitamos monomorfizar el\n" +"código completo que sigue para trabajar con `File` o `Stdin`." + +#: src\idioms/on-stack-dyn-dispatch.md:56 +#, fuzzy +msgid "The code needs more moving parts than the `Box`-based version:" +msgstr "El código necesita más partes móviles que la versión basada en `Box`:" + +#: 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 +#, fuzzy +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 "" +"Los recién llegados a Rust generalmente aprenderán que Rust requiere que " +"todas las variables sean\n" +"inicializado _antes de su uso_, por lo que es fácil pasar por alto el hecho " +"de que _unused_\n" +"las variables bien pueden no estar inicializadas. Rust trabaja muy duro para " +"garantizar que esto\n" +"funciona bien y solo los valores inicializados se eliminan al final de su\n" +"alcance." + +#: src\idioms/on-stack-dyn-dispatch.md:76 +#, fuzzy +msgid "The example meets all the constraints Rust places on us:" +msgstr "El ejemplo cumple con todas las restricciones que Rust nos impone:" + +#: src\idioms/on-stack-dyn-dispatch.md:78 +#, fuzzy +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 "" +"- Todas las variables se inicializan antes de usarlas (en este caso, " +"tomarlas prestadas)\n" +"- Cada variable solo contiene valores de un solo tipo. En nuestro ejemplo, " +"`stdin` es\n" +" de tipo `Stdin`, `file` es de tipo `File` y `readable` es de tipo `&mut " +"dyn Read`\n" +"- Cada valor prestado sobrevive a todas las referencias tomadas de él" + +#: src\idioms/on-stack-dyn-dispatch.md:85 +#, fuzzy +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 "" +"- [Finalización en destructores](dtor-finally.md) y\n" +" [Guardias RAII](../patterns/behavioural/RAII.md) pueden beneficiarse de un " +"control estricto sobre\n" +" vidas\n" +"- Para `Option<&T>`s de referencias (mutables) rellenadas condicionalmente, " +"se puede\n" +" inicialice una `Option` directamente y use su método [`.as_ref()`] para " +"obtener una\n" +" referencia opcional." + +#: src\idioms/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Idioms" +msgstr "# modismos FFI" + +#: src\idioms/ffi/intro.md:3 +#, fuzzy +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 "" +"Escribir código FFI es un curso completo en sí mismo.\n" +"Sin embargo, aquí hay varios modismos que pueden actuar como indicadores y " +"evitar\n" +"trampas para usuarios inexpertos de Rust `inseguro`." + +#: src\idioms/ffi/intro.md:7 +#, fuzzy +msgid "This section contains idioms that may be useful when doing FFI." +msgstr "Esta sección contiene modismos que pueden ser útiles al hacer FFI." + +#: src\idioms/ffi/intro.md:9 +#, fuzzy +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 "" +"1. [Errores idiomáticos](./errors.md) - Manejo de errores con códigos " +"enteros y\n" +" valores de retorno centinela (como punteros `NULL`)\n" +"\n" +"2. [Accepting Strings](./accepting-strings.md) con código inseguro mínimo\n" +"\n" +"3. [Pasar cadenas] (./pasar cadenas.md) a funciones FFI" + +#: src\idioms/ffi/errors.md:1 +#, fuzzy +msgid "# Error Handling in FFI" +msgstr "# Manejo de errores en FFI" + +#: src\idioms/ffi/errors.md:5 +#, fuzzy +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 "" +"En idiomas extranjeros como C, los errores se representan mediante códigos " +"de retorno.\n" +"Sin embargo, el sistema de tipos de Rust permite obtener información de " +"error mucho más rica.\n" +"capturado y propagado a través de un tipo completo." + +#: src\idioms/ffi/errors.md:9 +#, fuzzy +msgid "" +"This best practice shows different kinds of error codes, and how to expose " +"them\n" +"in a usable way:" +msgstr "" +"Esta práctica recomendada muestra diferentes tipos de códigos de error y " +"cómo exponerlos\n" +"de una manera utilizable:" + +#: src\idioms/ffi/errors.md:12 +#, fuzzy +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 "" +"1. Las enumeraciones planas deben convertirse en números enteros y " +"devolverse como códigos.\n" +"2. Las enumeraciones estructuradas deben convertirse a un código entero con " +"un error de cadena\n" +" mensaje para el detalle.\n" +"3. Los tipos de error personalizados deben volverse \"transparentes\", con " +"una representación C." + +#: 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 +#, fuzzy +msgid "## Code Example" +msgstr "## Ejemplo de código" + +#: src\idioms/ffi/errors.md:19 +#, fuzzy +msgid "### Flat Enums" +msgstr "### Enumeraciones planas" + +#: 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 +#, fuzzy +msgid "### Structured Enums" +msgstr "### Enumeraciones estructuradas" + +#: 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 +#, fuzzy +msgid "### Custom Error Types" +msgstr "### Tipos de errores personalizados" + +#: 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 +#, fuzzy +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 "" +"Esto asegura que el idioma extranjero tenga un acceso claro a la información " +"de error.\n" +"sin comprometer en absoluto la API del código Rust." + +#: src\idioms/ffi/errors.md:138 +#, fuzzy +msgid "" +"It's a lot of typing, and some types may not be able to be converted easily\n" +"to C." +msgstr "" +"Es mucho escribir, y es posible que algunos tipos no se puedan convertir " +"fácilmente\n" +"a c" + +#: src\idioms/ffi/accepting-strings.md:1 +#, fuzzy +msgid "# Accepting Strings" +msgstr "# Aceptar cadenas" + +#: src\idioms/ffi/accepting-strings.md:5 +#, fuzzy +msgid "" +"When accepting strings via FFI through pointers, there are two principles " +"that\n" +"should be followed:" +msgstr "" +"Al aceptar cadenas a través de FFI a través de punteros, hay dos principios " +"que\n" +"debe ser seguido:" + +#: src\idioms/ffi/accepting-strings.md:8 +#, fuzzy +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 "" +"1. Mantenga las cadenas extranjeras \"prestadas\", en lugar de copiarlas " +"directamente.\n" +"2. Minimice la cantidad de complejidad y el código \"inseguro\" involucrado " +"en la conversión\n" +" desde una cadena de estilo C hasta cadenas nativas de Rust." + +#: src\idioms/ffi/accepting-strings.md:14 +#, fuzzy +msgid "" +"The strings used in C have different behaviours to those used in Rust, " +"namely:" +msgstr "" +"Las cadenas utilizadas en C tienen comportamientos diferentes a los " +"utilizados en Rust, a saber:" + +#: src\idioms/ffi/accepting-strings.md:16 +#, fuzzy +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 "" +"- Las cadenas C terminan en nulo, mientras que las cadenas Rust almacenan su " +"longitud\n" +"- Las cadenas C pueden contener cualquier byte arbitrario distinto de cero, " +"mientras que las cadenas Rust deben ser\n" +" UTF-8\n" +"- Se accede a las cadenas C y se manipulan mediante operaciones de puntero " +"\"no seguras\".\n" +" mientras que las interacciones con cadenas de Rust pasan por métodos " +"seguros" + +#: src\idioms/ffi/accepting-strings.md:22 +#, fuzzy +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 "" +"La biblioteca estándar de Rust viene con equivalentes en C de `String` y " +"`&str` de Rust\n" +"llamados `CString` y `&CStr`, que nos permiten evitar mucha de la " +"complejidad\n" +"y código 'inseguro' involucrado en la conversión entre cadenas C y cadenas " +"Rust." + +#: src\idioms/ffi/accepting-strings.md:26 +#, fuzzy +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 "" +"El tipo `&CStr` también nos permite trabajar con datos prestados, lo que " +"significa pasar\n" +"cadenas entre Rust y C es una operación de costo cero." + +#: 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 +#, fuzzy +msgid "The example is is written to ensure that:" +msgstr "El ejemplo está escrito para garantizar que:" + +#: src\idioms/ffi/accepting-strings.md:72 +#, fuzzy +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 "" +"1. El bloque \"inseguro\" es lo más pequeño posible.\n" +"2. El puntero con una vida útil \"sin seguimiento\" se convierte en un " +"puntero compartido \"seguido\"\n" +" referencia" + +#: src\idioms/ffi/accepting-strings.md:76 +#, fuzzy +msgid "Consider an alternative, where the string is actually copied:" +msgstr "Considere una alternativa, donde la cadena en realidad se copia:" + +#: 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 +#, fuzzy +msgid "This code in inferior to the original in two respects:" +msgstr "Este código es inferior al original en dos aspectos:" + +#: src\idioms/ffi/accepting-strings.md:122 +#, fuzzy +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 "" +"1. Hay mucho más código \"inseguro\" y, lo que es más importante, más " +"invariantes.\n" +" debe sostener.\n" +"2. Debido a la extensa aritmética requerida, hay un error en esta versión\n" +" que casos Rust `comportamiento indefinido`." + +#: src\idioms/ffi/accepting-strings.md:127 +#, fuzzy +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 "" +"El error aquí es un simple error en la aritmética de punteros: la cadena fue " +"copiada,\n" +"todos los `msg_len` bytes del mismo. Sin embargo, el terminador `NUL` al " +"final no lo era." + +#: src\idioms/ffi/accepting-strings.md:130 +#, fuzzy +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 "" +"Luego, el Vector tenía su tamaño _establecido_ en la longitud de la _cadena " +"con relleno cero_ --\n" +"en lugar de _redimensionarlo_, lo que podría haber agregado un cero al " +"final.\n" +"Como resultado, el último byte del Vector es una memoria no inicializada.\n" +"Cuando se crea el `CString` en la parte inferior del bloque, se lee el\n" +"¡El vector causará un \"comportamiento indefinido\"!" + +#: src\idioms/ffi/accepting-strings.md:136 +#, fuzzy +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 "" +"Como muchos de estos problemas, este sería un problema difícil de rastrear.\n" +"A veces entraba en pánico porque la cadena no era `UTF-8`, a veces\n" +"poner un carácter extraño al final de la cadena, a veces simplemente\n" +"chocar completamente." + +#: src\idioms/ffi/accepting-strings.md:143 +#: src\idioms/ffi/passing-strings.md:105 +#, fuzzy +msgid "None?" +msgstr "¿Ninguno?" + +#: src\idioms/ffi/passing-strings.md:1 +#, fuzzy +msgid "# Passing Strings" +msgstr "# Cuerdas de paso" + +#: src\idioms/ffi/passing-strings.md:5 +#, fuzzy +msgid "" +"When passing strings to FFI functions, there are four principles that should " +"be\n" +"followed:" +msgstr "" +"Al pasar cadenas a funciones FFI, hay cuatro principios que deben ser\n" +"seguido:" + +#: src\idioms/ffi/passing-strings.md:8 +#, fuzzy +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 "" +"1. Haga que la vida útil de las cadenas propias sea lo más larga posible.\n" +"2. Minimice el código \"inseguro\" durante la conversión.\n" +"3. Si el código C puede modificar los datos de la cadena, use `Vec` en lugar " +"de `CString`.\n" +"4. A menos que la API de función externa lo requiera, la propiedad de la " +"cadena\n" +" no debe transferirse al destinatario." + +#: src\idioms/ffi/passing-strings.md:16 +#, fuzzy +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 "" +"Rust tiene soporte incorporado para cadenas de estilo C con su `CString` y " +"`CStr`\n" +"tipos Sin embargo, hay diferentes enfoques que uno puede tomar con cadenas " +"que\n" +"se envían a una llamada de función externa desde una función de Rust." + +#: src\idioms/ffi/passing-strings.md:20 +#, fuzzy +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 "" +"La mejor práctica es simple: use `CString` de tal manera que minimice\n" +"Código `inseguro`. Sin embargo, una advertencia secundaria es que\n" +"_el objeto debe vivir lo suficiente_, lo que significa que la vida útil debe " +"maximizarse.\n" +"Además, la documentación explica que \"viajar de ida y vuelta\" un `CString` " +"después\n" +"la modificación es UB, por lo que se necesita trabajo adicional en ese caso." + +#: 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 +#, fuzzy +msgid "The example is written in a way to ensure that:" +msgstr "El ejemplo está escrito de manera que se asegure que:" + +#: src\idioms/ffi/passing-strings.md:72 +#, fuzzy +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 "" +"1. El bloque \"inseguro\" es lo más pequeño posible.\n" +"2. El `CString` vive lo suficiente.\n" +"3. Los errores con typecasts siempre se propagan cuando es posible." + +#: src\idioms/ffi/passing-strings.md:76 +#, fuzzy +msgid "" +"A common mistake (so common it's in the documentation) is to not use the\n" +"variable in the first block:" +msgstr "" +"Un error común (tan común que está en la documentación) es no usar el\n" +"variable en el primer bloque:" + +#: 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 +#, fuzzy +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 "" +"Este código dará como resultado un puntero colgante, porque la vida útil " +"del\n" +"'CString' no se extiende por la creación del puntero, a diferencia de si una " +"referencia fuera\n" +"creado." + +#: src\idioms/ffi/passing-strings.md:98 +#, fuzzy +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 "" +"Otro problema que se plantea con frecuencia es que la inicialización de un " +"vector de 1k de\n" +"ceros es \"lento\". Sin embargo, las versiones recientes de Rust en realidad " +"optimizan eso\n" +"macro particular a una llamada a `zmalloc`, lo que significa que es tan " +"rápido como el operador\n" +"la capacidad del sistema para devolver la memoria puesta a cero (lo cual es " +"bastante rápido)." + +#: src\idioms/option-iter.md:1 +#, fuzzy +msgid "# Iterating over an `Option`" +msgstr "# Iterando sobre una `Opción`" + +#: src\idioms/option-iter.md:5 +#, fuzzy +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 "" +"`Opción` se puede ver como un contenedor que contiene cero o uno\n" +"elemento. En particular, implementa el rasgo `IntoIterator`, y como tal\n" +"se puede usar con código genérico que necesita ese tipo." + +#: src\idioms/option-iter.md:9 src\patterns/structural/small-crates.md:34 +#: src\patterns/structural/unsafe-mods.md:22 +#, fuzzy +msgid "## Examples" +msgstr "## Ejemplos" + +#: src\idioms/option-iter.md:11 +#, fuzzy +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 "" +"Dado que `Option` implementa `IntoIterator`, se puede usar como argumento " +"para\n" +"[`.extend()`](https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend):" + +#: 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 +#, fuzzy +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 "" +"Si necesita agregar una `Opción` al final de un iterador existente, puede\n" +"páselo a " +"[`.chain()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain):" + +#: 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 +#, fuzzy +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 "" +"Tenga en cuenta que si la `Opción` siempre es `Algunos`, entonces es más " +"idiomático de usar\n" +"[`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) en el\n" +"elemento en su lugar." + +#: src\idioms/option-iter.md:42 +#, fuzzy +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 "" +"Además, dado que `Option` implementa `IntoIterator`, es posible iterar " +"sobre\n" +"usando un bucle `for`. Esto es equivalente a emparejarlo con `if let " +"Some(...)`,\n" +"y en la mayoría de los casos deberías preferir lo último." + +#: src\idioms/option-iter.md:48 +#, fuzzy +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 "" +"- [`std::iter::once`](https://doc.rust-lang.org/std/iter/fn.once.html) es " +"un\n" +" iterador que produce exactamente un elemento. Es una alternativa más " +"legible a\n" +" `Algunos(foo).into_iter()`.\n" +"\n" +"- " +"[`Iterador::filter_map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map)\n" +" es una versión de " +"[`Iterator::map`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map),\n" +" especializado en funciones de mapeo que devuelven `Opción`.\n" +"\n" +"- La caja [`ref_slice`](https://crates.io/crates/ref_slice) proporciona " +"funciones\n" +" para convertir una `Opción` en una rebanada de cero o un elemento.\n" +"\n" +"- [Documentación para " +"`Option`](https://doc.rust-lang.org/std/option/enum.Option.html)" + +#: src\idioms/pass-var-to-closure.md:1 +#, fuzzy +msgid "# Pass variables to closure" +msgstr "# Pasar variables al cierre" + +#: src\idioms/pass-var-to-closure.md:5 +#, fuzzy +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 "" +"De forma predeterminada, los cierres capturan su entorno tomando prestado. O " +"puedes usar\n" +"cierre `mover` para mover todo el entorno. Sin embargo, a menudo desea " +"moverse solo\n" +"algunas variables para el cierre, darle copia de algunos datos, pasarlo por " +"referencia, o\n" +"realizar alguna otra transformación." + +#: src\idioms/pass-var-to-closure.md:10 +#, fuzzy +msgid "Use variable rebinding in separate scope for that." +msgstr "Use la revinculación de variables en un alcance separado para eso." + +#: src\idioms/pass-var-to-closure.md:14 +#, fuzzy +msgid "Use" +msgstr "Usar" + +#: 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 +#, fuzzy +msgid "instead of" +msgstr "en lugar de" + +#: 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 +#, fuzzy +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 "" +"Los datos copiados se agrupan junto con la definición de cierre, por lo que " +"su propósito es\n" +"más claras, y se dejarán caer inmediatamente incluso si no se consumen\n" +"por cierre." + +#: src\idioms/pass-var-to-closure.md:54 +#, fuzzy +msgid "" +"Closure uses same variable names as surrounding code whether data are copied " +"or\n" +"moved." +msgstr "" +"El cierre usa los mismos nombres de variables que el código circundante, ya " +"sea que los datos se copien o\n" +"movido." + +#: src\idioms/pass-var-to-closure.md:59 +#, fuzzy +msgid "Additional indentation of closure body." +msgstr "Muesca adicional del cuerpo del cierre." + +#: src\idioms/priv-extend.md:1 +#, fuzzy +msgid "# `#[non_exhaustive]` and private fields for extensibility" +msgstr "# `#[no_exhaustivo]` y campos privados para extensibilidad" + +#: src\idioms/priv-extend.md:5 +#, fuzzy +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 "" +"Existe un pequeño conjunto de escenarios en los que un autor de la " +"biblioteca puede querer agregar público\n" +"campos a una estructura pública o nuevas variantes a una enumeración sin " +"retroceder\n" +"compatibilidad." + +#: src\idioms/priv-extend.md:9 +#, fuzzy +msgid "Rust offers two solutions to this problem:" +msgstr "Rust ofrece dos soluciones a este problema:" + +#: src\idioms/priv-extend.md:11 +#, fuzzy +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 "" +"- Use `#[non_exhaustive]` en las variantes `struct`s, `enum`s y `enum`.\n" +" Para obtener documentación detallada sobre todos los lugares donde " +"`#[non_exhaustive]` puede ser\n" +" utilizado, consulte [los documentos] " +"(https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute).\n" +"\n" +"- Puede agregar un campo privado a una estructura para evitar que sea " +"directamente\n" +" instanciado o comparado con (ver Alternativa)" + +#: 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 +#, fuzzy +msgid "## Alternative: `Private fields` for structs" +msgstr "## Alternativa: `Campos privados` para estructuras" + +#: src\idioms/priv-extend.md:59 +#, fuzzy +msgid "" +"`#[non_exhaustive]` only works across crate boundaries.\n" +"Within a crate, the private field method may be used." +msgstr "" +"`#[non_exhaustive]` solo funciona a través de los límites de las cajas.\n" +"Dentro de una caja, se puede utilizar el método de campo privado." + +#: src\idioms/priv-extend.md:62 +#, fuzzy +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 "" +"Agregar un campo a una estructura es un cambio en su mayoría compatible con " +"versiones anteriores.\n" +"Sin embargo, si un cliente usa un patrón para deconstruir una instancia de " +"estructura,\n" +"podría nombrar todos los campos en la estructura y agregar uno nuevo " +"rompería eso\n" +"patrón.\n" +"El cliente podría nombrar algunos campos y usar `..` en el patrón, en cuyo " +"caso agregando\n" +"otro campo es compatible con versiones anteriores.\n" +"Hacer que al menos uno de los campos de la estructura sea privado obliga a " +"los clientes a usar este último\n" +"forma de patrones, asegurando que la estructura esté preparada para el " +"futuro." + +#: src\idioms/priv-extend.md:71 +#, fuzzy +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 "" +"La desventaja de este enfoque es que es posible que deba agregar un\n" +"campo a la estructura.\n" +"Puede usar el tipo `()` para que no haya sobrecarga de tiempo de ejecución y " +"anteponer `_` a\n" +"el nombre del campo para evitar la advertencia de campo no utilizado." + +#: 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 +#, fuzzy +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 "" +"En `struct`s, `#[non_exhaustive]` permite agregar campos adicionales al " +"revés\n" +"forma compatible.\n" +"También evitará que los clientes usen el constructor de estructuras, incluso " +"si todos los\n" +"Los campos son públicos.\n" +"Esto puede ser útil, pero vale la pena considerarlo si _quiere_ un campo " +"adicional\n" +"ser encontrado por los clientes como un error del compilador en lugar de " +"algo que puede ser silenciosamente\n" +"sin descubrir" + +#: src\idioms/priv-extend.md:95 +#, fuzzy +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 "" +"`#[non_exhaustive]` también se puede aplicar a las variantes de " +"enumeración.\n" +"Una variante `#[no_exhaustiva]` se comporta de la misma manera que una " +"estructura `#[no_exhaustiva]`." + +#: src\idioms/priv-extend.md:98 +#, fuzzy +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 "" +"Use esto deliberadamente y con precaución: incrementando la versión " +"principal al agregar\n" +"campos o variantes suele ser una mejor opción.\n" +"`#[non_exhaustive]` puede ser apropiado en escenarios en los que está " +"modelando un\n" +"recurso que puede cambiar fuera de sincronización con su biblioteca, pero no " +"es un propósito general\n" +"herramienta." + +#: src\idioms/priv-extend.md:104 +#, fuzzy +msgid "### Disadvantages" +msgstr "### Desventajas" + +#: src\idioms/priv-extend.md:106 +#, fuzzy +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 "" +"`#[non_exhaustive]` puede hacer que su código sea mucho menos ergonómico de " +"usar, especialmente cuando\n" +"forzado a manejar variantes de enumeración desconocidas.\n" +"Solo debe usarse cuando se requieren este tipo de evoluciones **sin**\n" +"incrementando la versión principal." + +#: 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 +#, fuzzy +msgid "" +"- [RFC introducing #[non_exhaustive] attribute for enums and " +"structs](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" +msgstr "" +"- [RFC presenta el atributo #[no_exhaustivo] para enumeraciones y " +"estructuras](https://github.com/rust-lang/rfcs/blob/master/text/2008-non-exhaustive.md)" + +#: src\idioms/rustdoc-init.md:1 +#, fuzzy +msgid "# Easy doc initialization\r" +msgstr "# Fácil inicialización de documentos\r" + +#: src\idioms/rustdoc-init.md:5 +#, fuzzy +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 "" +"Si una estructura requiere un esfuerzo significativo para inicializarse al " +"escribir documentos, puede ser\r\n" +"más rápido para envolver su ejemplo con una función de ayuda que toma la " +"estructura como una\r\n" +"argumento." + +#: src\idioms/rustdoc-init.md:9 +#, fuzzy +msgid "## Motivation\r" +msgstr "## Motivación\r" + +#: src\idioms/rustdoc-init.md:11 +#, fuzzy +msgid "" +"Sometimes there is a struct with multiple or complicated parameters and " +"several\r\n" +"methods. Each of these methods should have examples." +msgstr "" +"A veces hay una estructura con parámetros múltiples o complicados y " +"varios\r\n" +"métodos. Cada uno de estos métodos debe tener ejemplos." + +#: src\idioms/rustdoc-init.md:14 +#, fuzzy +msgid "For example:" +msgstr "Por ejemplo:" + +#: 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 +#, fuzzy +msgid "## Example\r" +msgstr "## Ejemplo\r" + +#: src\idioms/rustdoc-init.md:47 +#, fuzzy +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 "" +"En lugar de escribir todo este texto repetitivo para crear una `Conexión` " +"y\r\n" +"`Solicitud`, es más fácil simplemente crear una función auxiliar de " +"envoltura que tome\r\n" +"ellos como argumentos:" + +#: 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 +#, fuzzy +msgid "## Advantages\r" +msgstr "## Ventajas\r" + +#: src\idioms/rustdoc-init.md:79 +#, fuzzy +msgid "This is much more concise and avoids repetitive code in examples." +msgstr "Esto es mucho más conciso y evita el código repetitivo en los ejemplos." + +#: src\idioms/rustdoc-init.md:81 +#, fuzzy +msgid "## Disadvantages\r" +msgstr "## Desventajas\r" + +#: src\idioms/rustdoc-init.md:83 +#, fuzzy +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 "" +"Como el ejemplo está en una función, el código no se probará. Aunque seguirá " +"siendo\r\n" +"verificado para asegurarse de que compila cuando se ejecuta una `prueba de " +"carga`. Así que este patrón es\r\n" +"más útil cuando necesitas `no_run`. Con esto, no necesita agregar `no_run`." + +#: src\idioms/rustdoc-init.md:87 +#, fuzzy +msgid "## Discussion\r" +msgstr "## Discusión\r" + +#: src\idioms/rustdoc-init.md:89 +#, fuzzy +msgid "If assertions are not required this pattern works well." +msgstr "Si no se requieren aserciones, este patrón funciona bien." + +#: src\idioms/rustdoc-init.md:91 +#, fuzzy +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 "" +"Si lo son, una alternativa puede ser crear un método público para crear un " +"ayudante.\r\n" +"instancia que está anotada con `#[doc(hidden)]` (para que los usuarios no la " +"vean).\r\n" +"Entonces este método se puede llamar dentro de rustdoc porque es parte " +"del\r\n" +"API pública de crate." + +#: src\idioms/temporary-mutability.md:1 +#, fuzzy +msgid "# Temporary mutability" +msgstr "# Mutabilidad temporal" + +#: src\idioms/temporary-mutability.md:5 +#, fuzzy +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 "" +"A menudo es necesario preparar y procesar algunos datos, pero después de eso " +"los datos son\n" +"solo inspeccionado y nunca modificado. La intención puede hacerse explícita " +"redefiniendo\n" +"la variable mutable como inmutable." + +#: src\idioms/temporary-mutability.md:9 +#, fuzzy +msgid "" +"It can be done either by processing data within a nested block or by " +"redefining\n" +"the variable." +msgstr "" +"Se puede hacer procesando datos dentro de un bloque anidado o redefiniendo\n" +"La variable." + +#: src\idioms/temporary-mutability.md:14 +#, fuzzy +msgid "Say, vector must be sorted before usage." +msgstr "Digamos que el vector debe ordenarse antes de su uso." + +#: src\idioms/temporary-mutability.md:16 +#, fuzzy +msgid "Using nested block:" +msgstr "Usando bloque anidado:" + +#: 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 +#, fuzzy +msgid "Using variable rebinding:" +msgstr "Usando el reenlace variable:" + +#: 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 +#, fuzzy +msgid "" +"Compiler ensures that you don't accidentally mutate data after some point." +msgstr "" +"El compilador garantiza que no mute accidentalmente los datos después de " +"algún momento." + +#: src\idioms/temporary-mutability.md:44 +#, fuzzy +msgid "" +"Nested block requires additional indentation of block body.\n" +"One more line to return data from block or redefine variable." +msgstr "" +"El bloque anidado requiere sangría adicional del cuerpo del bloque.\n" +"Una línea más para devolver datos del bloque o redefinir variable." + +#: src\idioms/return-consumed-arg-on-error.md:1 +#, fuzzy +msgid "# Return consumed argument on error" +msgstr "# Devolver argumento consumido en caso de error" + +#: src\idioms/return-consumed-arg-on-error.md:5 +#, fuzzy +msgid "" +"If a fallible function consumes (moves) an argument, return that argument " +"back inside\n" +"an error." +msgstr "" +"Si una función falible consume (mueve) un argumento, devuelva ese argumento " +"al interior\n" +"un error." + +#: 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 +#, fuzzy +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 "" +"En caso de error, es posible que desee probar alguna forma alternativa o\n" +"reintentar la acción en caso de función no determinista. Pero si el " +"argumento\n" +"siempre se consume, se ve obligado a clonarlo en cada llamada, lo que\n" +"no es muy eficiente." + +#: src\idioms/return-consumed-arg-on-error.md:50 +#, fuzzy +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 "" +"La biblioteca estándar utiliza este enfoque en, p. Método " +"`String::from_utf8`.\n" +"Cuando se le da un vector que no contiene UTF-8 válido, un `FromUtf8Error`\n" +"es regresado.\n" +"Puede recuperar el vector original usando el método " +"`FromUtf8Error::into_bytes`." + +#: src\idioms/return-consumed-arg-on-error.md:57 +#, fuzzy +msgid "Better performance because of moving arguments whenever possible." +msgstr "" +"Mejor rendimiento debido a los argumentos en movimiento siempre que sea " +"posible." + +#: src\idioms/return-consumed-arg-on-error.md:61 +#, fuzzy +msgid "Slightly more complex error types." +msgstr "Tipos de error ligeramente más complejos." + +#: src\patterns/index.md:1 +#, fuzzy +msgid "# Design Patterns" +msgstr "# Patrones de diseño" + +#: src\patterns/index.md:3 +#, fuzzy +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 "" +"[Patrones de diseño](https://en.wikipedia.org/wiki/Software_design_pattern) " +"son\n" +"\"soluciones generales reutilizables para un problema común dentro de un " +"determinado\n" +"contexto en el diseño de software\". Los patrones de diseño son una " +"excelente manera de describir el\n" +"cultura de un lenguaje de programación. Los patrones de diseño son muy " +"específicos del idioma:\n" +"lo que es un patrón en un idioma puede ser innecesario en otro debido a una\n" +"característica del idioma, o imposible de expresar debido a la falta de una " +"característica." + +#: src\patterns/index.md:10 +#, fuzzy +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 "" +"Si se usan en exceso, los patrones de diseño pueden agregar una complejidad " +"innecesaria a los programas.\n" +"Sin embargo, son una excelente manera de compartir conocimientos de nivel " +"intermedio y avanzado.\n" +"sobre un lenguaje de programación." + +#: src\patterns/index.md:16 +#, fuzzy +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 "" +"Rust tiene muchas características únicas. Estas características nos brindan " +"un gran beneficio al eliminar\n" +"Clases enteras de problemas. Algunos de ellos también son patrones que son " +"_exclusivos_ de Rust." + +#: src\patterns/index.md:19 +#, fuzzy +msgid "## YAGNI" +msgstr "## YAGNI" + +#: src\patterns/index.md:21 +#, fuzzy +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 "" +"YAGNI es un acrónimo que significa `No lo vas a necesitar'.\n" +"Es un principio vital de diseño de software para aplicar mientras escribe " +"código." + +#: src\patterns/index.md:24 +#, fuzzy +msgid "> The best code I ever wrote was code I never wrote." +msgstr "> El mejor código que jamás escribí fue código que nunca escribí." + +#: src\patterns/index.md:26 +#, fuzzy +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 "" +"Si aplicamos YAGNI a los patrones de diseño, vemos que las características " +"de Rust nos permiten\n" +"tirar muchos patrones. Por ejemplo, no es necesario el [patrón de " +"estrategia] (https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"en Rust porque solo podemos usar " +"[traits](https://doc.rust-lang.org/book/traits.html)." + +#: src\patterns/behavioural/intro.md:1 +#, fuzzy +msgid "# Behavioural Patterns" +msgstr "# Patrones de comportamiento" + +#: src\patterns/behavioural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" +msgstr "De [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern):" + +#: src\patterns/behavioural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that identify common communication patterns among " +"objects.\n" +"> By doing so, these patterns increase flexibility in carrying out " +"communication." +msgstr "" +"> Patrones de diseño que identifican patrones de comunicación comunes entre " +"objetos.\n" +"> Al hacerlo, estos patrones aumentan la flexibilidad en la realización de " +"la comunicación." + +#: src\patterns/behavioural/command.md:1 +#, fuzzy +msgid "# Command" +msgstr "# Dominio" + +#: src\patterns/behavioural/command.md:5 +#, fuzzy +msgid "" +"The basic idea of the Command pattern is to separate out actions into its " +"own\n" +"objects and pass them as parameters." +msgstr "" +"La idea básica del patrón Comando es separar las acciones en sus propias\n" +"objetos y pasarlos como parámetros." + +#: src\patterns/behavioural/command.md:10 +#, fuzzy +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 "" +"Supongamos que tenemos una secuencia de acciones o transacciones " +"encapsuladas como objetos.\n" +"Queremos que estas acciones o comandos se ejecuten o invoquen en algún orden " +"más adelante\n" +"en tiempo diferente. Estos comandos también pueden activarse como resultado " +"de algún evento.\n" +"Por ejemplo, cuando un usuario presiona un botón o cuando llega un paquete " +"de datos.\n" +"Además, estos comandos se pueden deshacer. Esto puede ser útil para\n" +"operaciones de un editor. Podríamos querer almacenar registros de comandos " +"ejecutados para que\n" +"podríamos volver a aplicar los cambios más tarde si el sistema falla." + +#: src\patterns/behavioural/command.md:20 +#, fuzzy +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 "" +"Defina dos operaciones de base de datos `crear tabla` y `agregar campo`. " +"Cada uno de estos\n" +"operaciones es un comando que sabe cómo deshacer el comando, por ejemplo, " +"`drop table`\n" +"y `eliminar campo`. Cuando un usuario invoca una operación de migración de " +"base de datos, cada\n" +"el comando se ejecuta en el orden definido, y cuando el usuario invoca la " +"reversión\n" +"operación, entonces todo el conjunto de comandos se invoca en orden inverso." + +#: src\patterns/behavioural/command.md:26 +#, fuzzy +msgid "## Approach: Using trait objects" +msgstr "## Enfoque: uso de objetos de rasgos" + +#: src\patterns/behavioural/command.md:28 +#, fuzzy +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 "" +"Definimos un rasgo común que encapsula nuestro comando con dos operaciones\n" +"`ejecutar` y `retroceder`. Todas las `estructuras` de comando deben " +"implementar este rasgo." + +#: 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 +#, fuzzy +msgid "## Approach: Using function pointers" +msgstr "## Enfoque: uso de punteros de función" + +#: src\patterns/behavioural/command.md:97 +#, fuzzy +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 "" +"Podríamos seguir otro enfoque creando cada comando individual como\n" +"una función diferente y almacenar punteros de función para invocar estas " +"funciones más tarde\n" +"en un momento diferente. Dado que los punteros de función implementan los " +"tres rasgos `Fn`,\n" +"`FnMut` y `FnOnce` también podríamos pasar y almacenar cierres en lugar de\n" +"punteros de función." + +#: 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 +#, fuzzy +msgid "## Approach: Using `Fn` trait objects" +msgstr "## Enfoque: Uso de objetos de rasgos `Fn`" + +#: src\patterns/behavioural/command.md:152 +#, fuzzy +msgid "" +"Finally, instead of defining a common command trait we could store\n" +"each command implementing the `Fn` trait separately in vectors." +msgstr "" +"Finalmente, en lugar de definir un rasgo de comando común, podríamos " +"almacenar\n" +"cada comando implementa el rasgo `Fn` por separado en vectores." + +#: 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 +#, fuzzy +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 "" +"Si nuestros comandos son pequeños y pueden definirse como funciones o " +"pasarse como cierre\n" +"entonces podría ser preferible usar punteros de función, ya que no explota\n" +"despacho dinámico. Pero si nuestro comando es una estructura completa con un " +"montón de funciones\n" +"y variables definidas como módulo separado, entonces usar objetos de rasgos " +"sería\n" +"mas apropiado. Se puede encontrar un caso de aplicación en " +"[`actix`](https://actix.rs/),\n" +"que usa objetos de rasgos cuando registra una función de controlador para " +"rutas.\n" +"En caso de usar objetos de rasgo `Fn` podemos crear y usar comandos en el " +"mismo\n" +"tal como lo usamos en el caso de los punteros de función." + +#: src\patterns/behavioural/command.md:214 +#, fuzzy +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 "" +"Como rendimiento, siempre hay una compensación entre el rendimiento y el " +"código.\n" +"sencillez y organización. El despacho estático proporciona un rendimiento " +"más rápido, mientras que\n" +"El despacho dinámico proporciona flexibilidad cuando estructuramos nuestra " +"aplicación." + +#: src\patterns/behavioural/command.md:220 +#, fuzzy +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 "" +"- [Patrón de comando](https://en.wikipedia.org/wiki/Command_pattern)\n" +"\n" +"- [Otro ejemplo del patrón " +"`comando`](https://web.archive.org/web/20210223131236/https://chercher.tech/rust/command-design-pattern-rust)" + +#: src\patterns/behavioural/interpreter.md:1 +#, fuzzy +msgid "# Interpreter" +msgstr "# Intérprete" + +#: src\patterns/behavioural/interpreter.md:5 +#, fuzzy +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 "" +"Si un problema ocurre con mucha frecuencia y requiere pasos largos y " +"repetitivos para resolverlo\n" +"entonces las instancias del problema podrían expresarse en un lenguaje " +"simple y un\n" +"El objeto intérprete podría resolverlo interpretando las oraciones escritas " +"en este\n" +"lenguaje sencillo" + +#: src\patterns/behavioural/interpreter.md:10 +#, fuzzy +msgid "Basically, for any kind of problems we define:" +msgstr "Básicamente, para cualquier tipo de problema definimos:" + +#: src\patterns/behavioural/interpreter.md:12 +#, fuzzy +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 "" +"- Un [idioma específico del " +"dominio](https://en.wikipedia.org/wiki/Domain-specific_language),\n" +"- Una gramática para este idioma,\n" +"- Un intérprete que resuelve las instancias del problema." + +#: src\patterns/behavioural/interpreter.md:18 +#, fuzzy +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 "" +"Nuestro objetivo es traducir expresiones matemáticas simples en expresiones " +"postfix\n" +"(o [notación polaca " +"inversa](https://en.wikipedia.org/wiki/Reverse_Polish_notation))\n" +"Para simplificar, nuestras expresiones constan de diez dígitos `0`, ..., `9` " +"y dos\n" +"operaciones `+`, `-`. Por ejemplo, la expresión `2 + 4` se traduce a\n" +"`2 4 +`." + +#: src\patterns/behavioural/interpreter.md:24 +#, fuzzy +msgid "## Context Free Grammar for our problem" +msgstr "## Gramática libre de contexto para nuestro problema" + +#: src\patterns/behavioural/interpreter.md:26 +#, fuzzy +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 "" +"Nuestra tarea es traducir expresiones infijas a postfijas. Definamos un " +"contexto\n" +"gramática libre para un conjunto de expresiones infijas sobre `0`, ..., `9`, " +"`+` y `-`,\n" +"dónde:" + +#: src\patterns/behavioural/interpreter.md:30 +#, fuzzy +msgid "" +"- Terminal symbols: `0`, `...`, `9`, `+`, `-`\n" +"- Non-terminal symbols: `exp`, `term`\n" +"- Start symbol is `exp`\n" +"- And the following are production rules" +msgstr "" +"- Símbolos terminales: `0`, `...`, `9`, `+`, `-`\n" +"- Símbolos no terminales: `exp`, `term`\n" +"- El símbolo de inicio es `exp`\n" +"- Y las siguientes son reglas de producción." + +#: 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 +#, fuzzy +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 "" +"**NOTA:** Esta gramática debe transformarse aún más dependiendo de lo que " +"estemos haciendo\n" +"hacer con eso Por ejemplo, es posible que necesitemos eliminar la " +"recursividad por la izquierda. Para más\n" +"detalles, consulte [Compiladores: principios, técnicas y herramientas] " +"(https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)\n" +"(también conocido como Libro del Dragón)." + +#: src\patterns/behavioural/interpreter.md:47 +#, fuzzy +msgid "## Solution" +msgstr "## Solución" + +#: src\patterns/behavioural/interpreter.md:49 +#, fuzzy +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 "" +"Simplemente implementamos un analizador de descenso recursivo. En aras de la " +"simplicidad, el código\n" +"entra en pánico cuando una expresión es sintácticamente incorrecta (por " +"ejemplo, `2-34` o `2+5-`\n" +"están mal según la definición gramatical)." + +#: 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 +#, fuzzy +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 "" +"Puede haber una percepción errónea de que el patrón de diseño del Intérprete " +"se trata de diseño\n" +"gramáticas para lenguajes formales e implementación de analizadores para " +"estas gramáticas.\n" +"De hecho, este patrón se trata de expresar instancias de problemas en una " +"forma más específica.\n" +"e implementando funciones/clases/estructuras que resuelven estas instancias " +"de problemas.\n" +"El lenguaje Rust tiene `macro_rules!` que nos permiten definir sintaxis y " +"reglas especiales\n" +"sobre cómo expandir esta sintaxis en el código fuente." + +#: src\patterns/behavioural/interpreter.md:112 +#, fuzzy +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 "" +"En el siguiente ejemplo, creamos un `macro_rules!` simple que calcula\n" +"[Longitud euclidiana](https://en.wikipedia.org/wiki/Euclidean_distance) de " +"`n`\n" +"vectores dimensionales. Escribir `norma!(x,1,2)` podría ser más fácil de " +"expresar y más\n" +"más eficiente que empaquetar `x,1,2` en un `Vec` y llamar a una función " +"informática\n" +"la longitud." + +#: 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 +#, fuzzy +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 "" +"- [Patrón de intérprete](https://en.wikipedia.org/wiki/Interpreter_pattern)\n" +"- [Gramática libre de " +"contexto](https://en.wikipedia.org/wiki/Context-free_grammar)\n" +"- [macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)" + +#: src\patterns/behavioural/newtype.md:1 +#, fuzzy +msgid "# Newtype" +msgstr "# Nuevo tipo" + +#: src\patterns/behavioural/newtype.md:3 +#, fuzzy +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 "" +"¿Qué pasa si en algunos casos queremos que un tipo se comporte de manera " +"similar a otro tipo o\n" +"hacer cumplir algún comportamiento en tiempo de compilación cuando usar solo " +"alias de tipo sería\n" +"no ser suficiente?" + +#: src\patterns/behavioural/newtype.md:7 +#, fuzzy +msgid "" +"For example, if we want to create a custom `Display` implementation for " +"`String`\n" +"due to security considerations (e.g. passwords)." +msgstr "" +"Por ejemplo, si queremos crear una implementación `Display` personalizada " +"para `String`\n" +"debido a consideraciones de seguridad (por ejemplo, contraseñas)." + +#: src\patterns/behavioural/newtype.md:10 +#, fuzzy +msgid "" +"For such cases we could use the `Newtype` pattern to provide **type " +"safety**\n" +"and **encapsulation**." +msgstr "" +"Para tales casos, podríamos usar el patrón `Newtype` para proporcionar " +"**seguridad de tipo**\n" +"y **encapsulación**." + +#: src\patterns/behavioural/newtype.md:15 +#, fuzzy +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 "" +"Use una estructura de tupla con un solo campo para crear un contenedor opaco " +"para un tipo.\n" +"Esto crea un nuevo tipo, en lugar de un alias para un tipo (elementos " +"`tipo`)." + +#: 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 +#, fuzzy +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 "" +"La principal motivación para los nuevos tipos es la abstracción. Te permite " +"compartir\n" +"detalles de implementación entre tipos mientras controla con precisión la " +"interfaz.\n" +"Al usar un nuevo tipo en lugar de exponer el tipo de implementación como " +"parte de un\n" +"API, le permite cambiar la implementación de manera retrocompatible." + +#: src\patterns/behavioural/newtype.md:63 +#, fuzzy +msgid "" +"Newtypes can be used for distinguishing units, e.g., wrapping `f64` to give\n" +"distinguishable `Miles` and `Kilometres`." +msgstr "" +"Los tipos nuevos se pueden usar para distinguir unidades, por ejemplo, " +"envolviendo `f64` para dar\n" +"distinguibles `Millas` y `Kilómetros`." + +#: src\patterns/behavioural/newtype.md:68 +#, fuzzy +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 "" +"Los tipos wrapper y wrapper no son compatibles (a diferencia de usar\n" +"`tipo`), por lo que los usuarios del nuevo tipo nunca 'confundirán' el " +"envuelto y el envoltorio\n" +"tipos" + +#: src\patterns/behavioural/newtype.md:72 +#, fuzzy +msgid "Newtypes are a zero-cost abstraction - there is no runtime overhead." +msgstr "" +"Los tipos nuevos son una abstracción de costo cero: no hay sobrecarga de " +"tiempo de ejecución." + +#: src\patterns/behavioural/newtype.md:74 +#, fuzzy +msgid "" +"The privacy system ensures that users cannot access the wrapped type (if " +"the\n" +"field is private, which it is by default)." +msgstr "" +"El sistema de privacidad garantiza que los usuarios no puedan acceder al " +"tipo envuelto (si el\n" +"el campo es privado, que es por defecto)." + +#: src\patterns/behavioural/newtype.md:79 +#, fuzzy +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 "" +"La desventaja de los nuevos tipos (especialmente en comparación con los " +"alias de tipo) es que no\n" +"no hay soporte de idioma especial. Esto significa que puede haber _mucho_ " +"repetitivo.\n" +"Necesita un método de 'paso a través' para cada método que desee exponer en " +"el\n" +"tipo envuelto, y un impl para cada rasgo que desea implementar también para\n" +"el tipo de envoltura." + +#: src\patterns/behavioural/newtype.md:87 +#, fuzzy +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 "" +"Los tipos nuevos son muy comunes en el código de Rust. Las unidades de " +"abstracción o representación son las\n" +"usos más comunes, pero pueden ser utilizados por otras razones:" + +#: src\patterns/behavioural/newtype.md:90 +#, fuzzy +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 "" +"- restringir la funcionalidad (reducir las funciones expuestas o los rasgos " +"implementados),\n" +"- hacer que un tipo con semántica de copia tenga semántica de movimiento,\n" +"- abstracción proporcionando un tipo más concreto y ocultando así los tipos " +"internos,\n" +" p.ej.," + +#: src\patterns/behavioural/newtype.md:95 +msgid "" +"```rust,ignore\n" +"pub struct Foo(Bar);\n" +"```" +msgstr "" + +#: src\patterns/behavioural/newtype.md:99 +#, fuzzy +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 "" +"Aquí, 'Bar' podría ser un tipo genérico público y 'T1' y 'T2' son algunos " +"internos.\n" +"tipos Los usuarios de nuestro módulo no deberían saber que implementamos " +"`Foo` usando una `Bar`,\n" +"pero lo que realmente estamos ocultando aquí son los tipos `T1` y `T2`, y " +"cómo se usan\n" +"con `Barra`." + +#: src\patterns/behavioural/newtype.md:106 +#, fuzzy +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 "" +"- [Tipos avanzados en el " +"libro](https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety " +"-y-abstracción)\n" +"- [Nuevos tipos en Haskell](https://wiki.haskell.org/Newtype)\n" +"- [Escriba " +"alias](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), una caja para derivar " +"muchos\n" +" rasgos incorporados en newtypes.\n" +"- [El patrón Newtype en " +"Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)" + +#: src\patterns/behavioural/RAII.md:1 +#, fuzzy +msgid "# RAII with guards" +msgstr "# RAII con guardias" + +#: src\patterns/behavioural/RAII.md:5 +#, fuzzy +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 "" +"[RAII][wikipedia] significa \"Adquisición de recursos es inicialización\", " +"que es una\n" +"terrible nombre La esencia del patrón es que la inicialización de recursos " +"se realiza\n" +"en el constructor de un objeto y finalización en el destructor. este patrón\n" +"se extiende en Rust usando un objeto RAII como guardián de algún recurso y " +"confiando\n" +"en el sistema de tipos para garantizar que el acceso siempre esté mediado " +"por el objeto guardián." + +#: src\patterns/behavioural/RAII.md:13 +#, fuzzy +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 "" +"Los protectores Mutex son el ejemplo clásico de este patrón de la biblioteca " +"estándar (este\n" +"es una versión simplificada de la implementación real):" + +#: 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 +#, fuzzy +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 "" +"Cuando un recurso debe finalizarse después de su uso, se puede usar RAII " +"para hacer esto\n" +"finalización Si es un error acceder a ese recurso después de la " +"finalización, entonces\n" +"este patrón se puede utilizar para evitar tales errores." + +#: src\patterns/behavioural/RAII.md:80 +#, fuzzy +msgid "" +"Prevents errors where a resource is not finalised and where a resource is " +"used\n" +"after finalisation." +msgstr "" +"Previene errores donde un recurso no está finalizado y donde se usa un " +"recurso\n" +"después de la finalización." + +#: src\patterns/behavioural/RAII.md:85 +#, fuzzy +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 "" +"RAII es un patrón útil para garantizar que los recursos se desasignen o\n" +"finalizado. Podemos hacer uso del verificador de préstamos en Rust para " +"evitar estáticamente\n" +"errores derivados del uso de recursos después de la finalización." + +#: src\patterns/behavioural/RAII.md:89 +#, fuzzy +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 "" +"El objetivo principal del verificador de préstamos es garantizar que las " +"referencias a los datos no\n" +"sobrevivir a esos datos. El patrón de protección RAII funciona porque el " +"objeto de protección\n" +"contiene una referencia al recurso subyacente y solo expone tal\n" +"referencias Rust asegura que el guardia no puede sobrevivir al recurso " +"subyacente\n" +"y que las referencias al recurso mediado por la guardia no pueden sobrevivir " +"al\n" +"guardia. Para ver cómo funciona esto, es útil examinar la firma de `deref`\n" +"sin elisión de por vida:" + +#: 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 +#, fuzzy +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 "" +"La referencia devuelta al recurso tiene la misma duración que `self` " +"(`'a`).\n" +"Por lo tanto, el verificador de préstamos garantiza que la vida útil de la " +"referencia a `T`\n" +"es más corto que el tiempo de vida de `sí mismo`." + +#: src\patterns/behavioural/RAII.md:107 +#, fuzzy +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 "" +"Tenga en cuenta que la implementación de `Deref` no es una parte central de " +"este patrón, solo hace\n" +"utilizando el objeto de guardia más ergonómico. Implementando un método " +"`get` en el guardia\n" +"funciona igual de bien." + +#: src\patterns/behavioural/RAII.md:113 +#, fuzzy +msgid "[Finalisation in destructors idiom](../../idioms/dtor-finally.md)" +msgstr "[Finalización en idioma de destructores](../../idioms/dtor-finally.md)" + +#: src\patterns/behavioural/RAII.md:115 +#, fuzzy +msgid "" +"RAII is a common pattern in C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." +msgstr "" +"RAII es un patrón común en C++: " +"[cppreference.com](http://en.cppreference.com/w/cpp/language/raii),\n" +"[wikipedia][wikipedia]." + +#: src\patterns/behavioural/RAII.md:120 +#, fuzzy +msgid "" +"[Style guide " +"entry](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(currently just a placeholder)." +msgstr "" +"[Entrada de guía de " +"estilo](https://doc.rust-lang.org/1.0.0/style/ownership/raii.html)\n" +"(actualmente solo un marcador de posición)." + +#: src\patterns/behavioural/strategy.md:1 +#, fuzzy +msgid "# Strategy (aka Policy)" +msgstr "# Estrategia (también conocida como Política)" + +#: src\patterns/behavioural/strategy.md:5 +#, fuzzy +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 "" +"El [patrón de diseño de estrategia] " +"(https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"es una técnica que permite la separación de preocupaciones.\n" +"También permite desacoplar módulos de software a través de [Inversión de " +"dependencia] (https://en.wikipedia.org/wiki/Dependency_inversion_principle)." + +#: src\patterns/behavioural/strategy.md:9 +#, fuzzy +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 "" +"La idea básica detrás del patrón de estrategia es que, dado un algoritmo que " +"resuelve\n" +"un problema particular, definimos solo el esqueleto del algoritmo en un " +"resumen\n" +"nivel, y separamos la implementación del algoritmo específico en diferentes " +"partes." + +#: src\patterns/behavioural/strategy.md:13 +#, fuzzy +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 "" +"De esta forma, un cliente que utilice el algoritmo puede elegir una " +"implementación específica,\n" +"mientras que el flujo de trabajo general del algoritmo sigue siendo el " +"mismo. En otras palabras, el resumen\n" +"especificación de la clase no depende de la implementación específica de la\n" +"clase derivada, pero la implementación específica debe adherirse a la " +"especificación abstracta.\n" +"Es por eso que lo llamamos \"Inversión de Dependencia\"." + +#: src\patterns/behavioural/strategy.md:21 +#, fuzzy +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 "" +"Imagina que estamos trabajando en un proyecto que genera informes todos los " +"meses.\n" +"Necesitamos que los informes se generen en diferentes formatos " +"(estrategias), por ejemplo,\n" +"en formatos `JSON` o `Plain Text`.\n" +"Pero las cosas varían con el tiempo, y no sabemos qué tipo de requisito " +"podemos obtener\n" +"en el futuro. Por ejemplo, es posible que necesitemos generar nuestro " +"informe en un formato completamente nuevo.\n" +"formato, o simplemente modificar uno de los formatos existentes." + +#: src\patterns/behavioural/strategy.md:30 +#, fuzzy +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 "" +"En este ejemplo, nuestras invariantes (o abstracciones) son `Context`, " +"`Formatter`,\n" +"y `Report`, mientras que `Text` y `Json` son nuestras estructuras de " +"estrategia. Estas estrategias\n" +"tiene que implementar el rasgo `Formatter`." + +#: 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 +#, fuzzy +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 "" +"La principal ventaja es la separación de preocupaciones. Por ejemplo, en " +"este caso `Informe`\n" +"no sabe nada sobre implementaciones específicas de `Json` y `Text`,\n" +"mientras que las implementaciones de salida no se preocupan por cómo se " +"preprocesan los datos,\n" +"almacenado y obtenido. Lo único que tienen que saber es el contexto y una " +"determinada\n" +"rasgo y método a implementar, es decir, `Formatter` y `run`." + +#: src\patterns/behavioural/strategy.md:106 +#, fuzzy +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 "" +"Para cada estrategia debe implementarse al menos un módulo, por lo que el " +"número de módulos\n" +"aumenta con el número de estrategias. Si hay muchas estrategias para elegir\n" +"luego los usuarios tienen que saber en qué se diferencian las estrategias " +"entre sí." + +#: src\patterns/behavioural/strategy.md:112 +#, fuzzy +msgid "" +"In the previous example all strategies are implemented in a single file.\n" +"Ways of providing different strategies includes:" +msgstr "" +"En el ejemplo anterior todas las estrategias se implementan en un solo " +"archivo.\n" +"Las formas de proporcionar diferentes estrategias incluyen:" + +#: src\patterns/behavioural/strategy.md:115 +#, fuzzy +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 "" +"- Todo en un archivo (como se muestra en este ejemplo, similar a estar " +"separados como módulos)\n" +"- Separados como módulos, p. módulo `formateador::json`, módulo " +"`formateador::texto`\n" +"- Use indicadores de características del compilador, p. función `json`, " +"función `texto`\n" +"- Separados como cajas, p. caja `json`, caja `texto`" + +#: src\patterns/behavioural/strategy.md:120 +#, fuzzy +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 "" +"Serde crate es un buen ejemplo del patrón 'Estrategia' en acción. Serde " +"permite\n" +"[personalización completa](https://serde.rs/custom-serialization.html) de la " +"serialización\n" +"comportamiento implementando manualmente `Serialize` y `Deserialize` rasgos " +"para nuestro\n" +"tipo. Por ejemplo, podríamos intercambiar fácilmente `serde_json` con " +"`serde_cbor` ya que\n" +"exponer métodos similares. Tener esto hace que el asistente cree " +"`serde_transcode` mucho\n" +"más útil y ergonómico." + +#: src\patterns/behavioural/strategy.md:127 +#, fuzzy +msgid "" +"However, we don't need to use traits in order to design this pattern in Rust." +msgstr "" +"Sin embargo, no necesitamos usar rasgos para diseñar este patrón en Rust." + +#: src\patterns/behavioural/strategy.md:129 +#, fuzzy +msgid "" +"The following toy example demonstrates the idea of the Strategy pattern " +"using Rust\n" +"`closures`:" +msgstr "" +"El siguiente ejemplo de juguete demuestra la idea del patrón de estrategia " +"usando Rust\n" +"`cierres`:" + +#: 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 +#, fuzzy +msgid "In fact, Rust already uses this idea for `Options`'s `map` method:" +msgstr "De hecho, Rust ya usa esta idea para el método `map` de `Options`:" + +#: 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 +#, fuzzy +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 "" +"- [Patrón de estrategia](https://en.wikipedia.org/wiki/Strategy_pattern)\n" +"- [Inyección de " +"dependencia](https://en.wikipedia.org/wiki/Dependency_injection)\n" +"- [Diseño basado en políticas] " +"(https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design)" + +#: src\patterns/behavioural/visitor.md:1 +#, fuzzy +msgid "# Visitor" +msgstr "# Visitante" + +#: src\patterns/behavioural/visitor.md:5 +#, fuzzy +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 "" +"Un visitante encapsula un algoritmo que opera sobre un heterogéneo\n" +"colección de objetos. Permite escribir múltiples algoritmos diferentes.\n" +"sobre los mismos datos sin tener que modificar los datos (o su principal\n" +"comportamiento)." + +#: src\patterns/behavioural/visitor.md:10 +#, fuzzy +msgid "" +"Furthermore, the visitor pattern allows separating the traversal of\n" +"a collection of objects from the operations performed on each object." +msgstr "" +"Además, el patrón de visitante permite separar el recorrido de\n" +"una colección de objetos de las operaciones realizadas en cada objeto." + +#: 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 +#, fuzzy +msgid "" +"One could implement further visitors, for example a type checker, without " +"having\n" +"to modify the AST data." +msgstr "" +"Se podrían implementar más visitantes, por ejemplo, un verificador de tipos, " +"sin tener\n" +"para modificar los datos AST." + +#: src\patterns/behavioural/visitor.md:74 +#, fuzzy +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 "" +"El patrón de visitante es útil en cualquier lugar al que desee aplicar un " +"algoritmo\n" +"datos heterogéneos. Si los datos son homogéneos, puede usar un patrón " +"similar a un iterador.\n" +"El uso de un objeto de visitante (en lugar de un enfoque funcional) le " +"permite al visitante\n" +"tener estado y así comunicar información entre nodos." + +#: src\patterns/behavioural/visitor.md:81 +#, fuzzy +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 "" +"Es común que los métodos `visit_*` devuelvan void (a diferencia del método\n" +"ejemplo). En ese caso, es posible factorizar el código transversal y " +"compartir\n" +"entre algoritmos (y también para proporcionar métodos predeterminados de " +"noop). En óxido, el\n" +"La forma común de hacer esto es proporcionar funciones `walk_*` para cada " +"dato. Para\n" +"ejemplo," + +#: 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 +#, fuzzy +msgid "" +"In other languages (e.g., Java) it is common for data to have an `accept` " +"method\n" +"which performs the same duty." +msgstr "" +"En otros lenguajes (por ejemplo, Java) es común que los datos tengan un " +"método `aceptar`\n" +"que cumple el mismo deber." + +#: src\patterns/behavioural/visitor.md:108 +#, fuzzy +msgid "The visitor pattern is a common pattern in most OO languages." +msgstr "" +"El patrón de visitante es un patrón común en la mayoría de los lenguajes OO." + +#: src\patterns/behavioural/visitor.md:110 +#, fuzzy +msgid "[Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern)" +msgstr "[Artículo de Wikipedia](https://en.wikipedia.org/wiki/Visitor_pattern)" + +#: src\patterns/behavioural/visitor.md:112 +#, fuzzy +msgid "" +"The [fold](../creational/fold.md) pattern is similar to visitor but " +"produces\n" +"a new version of the visited data structure." +msgstr "" +"El patrón [fold](../creational/fold.md) es similar al visitante pero " +"produce\n" +"una nueva versión de la estructura de datos visitada." + +#: src\patterns/creational/intro.md:1 +#, fuzzy +msgid "# Creational Patterns" +msgstr "# Patrones de creación" + +#: src\patterns/creational/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" +msgstr "De [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern):" + +#: src\patterns/creational/intro.md:5 +#, fuzzy +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 "" +"> Patrones de diseño que se ocupan de los mecanismos de creación de objetos, " +"tratando de crear objetos\n" +"> de una manera adecuada a la situación. La forma básica de creación de " +"objetos podría\n" +"> resultar en problemas de diseño o en complejidad adicional al diseño. " +"diseño creacional\n" +"> los patrones resuelven este problema controlando de alguna manera la " +"creación de este objeto." + +#: src\patterns/creational/builder.md:1 +#, fuzzy +msgid "# Builder" +msgstr "# Constructor" + +#: src\patterns/creational/builder.md:5 +#, fuzzy +msgid "Construct an object with calls to a builder helper." +msgstr "Construya un objeto con llamadas a un asistente de construcción." + +#: 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 +#, fuzzy +msgid "" +"Useful when you would otherwise require many constructors or where\n" +"construction has side effects." +msgstr "" +"Útil cuando de otro modo necesitaría muchos constructores o donde\n" +"la construcción tiene efectos secundarios." + +#: src\patterns/creational/builder.md:70 +#, fuzzy +msgid "Separates methods for building from other methods." +msgstr "Separa los métodos de construcción de otros métodos." + +#: src\patterns/creational/builder.md:72 +#, fuzzy +msgid "Prevents proliferation of constructors." +msgstr "Evita la proliferación de constructores." + +#: src\patterns/creational/builder.md:74 +#, fuzzy +msgid "" +"Can be used for one-liner initialisation as well as more complex " +"construction." +msgstr "" +"Se puede utilizar para la inicialización de una sola línea, así como para " +"construcciones más complejas." + +#: src\patterns/creational/builder.md:78 +#, fuzzy +msgid "" +"More complex than creating a struct object directly, or a simple " +"constructor\n" +"function." +msgstr "" +"Más complejo que crear un objeto de estructura directamente o un constructor " +"simple\n" +"función." + +#: src\patterns/creational/builder.md:83 +#, fuzzy +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 "" +"Este patrón se ve con más frecuencia en Rust (y para objetos más simples) " +"que en\n" +"muchos otros lenguajes porque Rust carece de sobrecarga. Ya que solo puedes " +"tener un\n" +"método único con un nombre dado, tener múltiples constructores es menos " +"agradable en\n" +"Rust que en C++, Java u otros." + +#: src\patterns/creational/builder.md:88 +#, fuzzy +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 "" +"Este patrón se usa a menudo cuando el objeto constructor es útil por derecho " +"propio,\n" +"en lugar de ser sólo un constructor. Por ejemplo, ver\n" +"[`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html)\n" +"es un constructor para " +"[`Child`](https://doc.rust-lang.org/std/process/struct.Child.html)\n" +"(un proceso). En estos casos, no se utiliza el patrón de nomenclatura `T` y " +"`TBuilder`." + +#: src\patterns/creational/builder.md:94 +#, fuzzy +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 "" +"El ejemplo toma y devuelve el constructor por valor. A menudo es más " +"ergonómico.\n" +"(y más eficiente) para tomar y devolver el constructor como una referencia " +"mutable. El\n" +"El verificador de préstamos hace que esto funcione de forma natural. Este " +"enfoque tiene la ventaja de que\n" +"uno puede escribir código como" + +#: 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 +#, fuzzy +msgid "as well as the `FooBuilder::new().a().b().build()` style." +msgstr "así como el estilo `FooBuilder::new().a().b().build()`." + +#: src\patterns/creational/builder.md:110 +#, fuzzy +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 "" +"- [Descripción en la guía de " +"estilo](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), una caja para " +"automáticamente\n" +" implementar este patrón mientras se evita el repetitivo.\n" +"- [Patrón de constructor](../../idioms/ctor.md) para cuando la construcción " +"es más sencilla.\n" +"- [Patrón de constructor " +"(wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern)\n" +"- [Construcción de valores " +"complejos](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder)" + +#: src\patterns/creational/fold.md:1 +#, fuzzy +msgid "# Fold" +msgstr "# Doblar" + +#: src\patterns/creational/fold.md:5 +#, fuzzy +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 "" +"Ejecute un algoritmo sobre cada elemento en una colección de datos para " +"crear un nuevo elemento,\n" +"creando así una colección completamente nueva." + +#: src\patterns/creational/fold.md:8 +#, fuzzy +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 "" +"La etimología aquí no está clara para mí. Los términos 'doblar' y 'carpeta' " +"se utilizan\n" +"en el compilador de Rust, aunque me parece más un mapa que un\n" +"doblar en el sentido habitual. Consulte la discusión a continuación para " +"obtener más detalles." + +#: 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 +#, fuzzy +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 "" +"El resultado de ejecutar `Renamer` en un AST es un nuevo AST idéntico al " +"antiguo\n" +"one, pero con todos los nombres cambiados a `foo`. Una carpeta de la vida " +"real podría tener algunos\n" +"estado preservado entre nodos en la estructura misma." + +#: src\patterns/creational/fold.md:69 +#, fuzzy +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 "" +"También se puede definir una carpeta para asignar una estructura de datos a " +"otra diferente (pero\n" +"generalmente similar) estructura de datos. Por ejemplo, podríamos convertir " +"un AST en un HIR\n" +"árbol (HIR significa representación intermedia de alto nivel)." + +#: src\patterns/creational/fold.md:75 +#, fuzzy +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 "" +"Es común querer mapear una estructura de datos realizando alguna operación " +"en\n" +"cada nodo de la estructura. Para operaciones simples en estructuras de datos " +"simples,\n" +"esto se puede hacer usando `Iterator::map`. Para operaciones más complejas, " +"tal vez\n" +"donde los nodos anteriores pueden afectar la operación en nodos posteriores, " +"o donde la iteración\n" +"sobre la estructura de datos no es trivial, usar el patrón de plegado es " +"más\n" +"adecuado." + +#: src\patterns/creational/fold.md:82 +#, fuzzy +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 "" +"Al igual que el patrón de visitante, el patrón de plegado nos permite " +"separar el recorrido de un\n" +"estructura de datos de las operaciones realizadas a cada nodo." + +#: src\patterns/creational/fold.md:87 +#, fuzzy +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 "" +"Mapear estructuras de datos de esta manera es común en lenguajes " +"funcionales. en OO\n" +"idiomas, sería más común mutar la estructura de datos en su lugar. El\n" +"El enfoque 'funcional' es común en Rust, principalmente debido a la " +"preferencia por\n" +"inmutabilidad. El uso de estructuras de datos nuevas, en lugar de mutar las " +"antiguas, hace\n" +"razonar sobre el código es más fácil en la mayoría de las circunstancias." + +#: src\patterns/creational/fold.md:93 +#, fuzzy +msgid "" +"The trade-off between efficiency and reusability can be tweaked by changing " +"how\n" +"nodes are accepted by the `fold_*` methods." +msgstr "" +"La compensación entre la eficiencia y la reutilización se puede ajustar " +"cambiando cómo\n" +"los nodos son aceptados por los métodos `fold_*`." + +#: src\patterns/creational/fold.md:96 +#, fuzzy +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 "" +"En el ejemplo anterior, operamos con punteros `Box`. Ya que estos son dueños " +"de sus datos\n" +"exclusivamente, la copia original de la estructura de datos no puede ser " +"reutilizada. Sobre el\n" +"Por otro lado, si un nodo no se cambia, reutilizarlo es muy eficiente." + +#: 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 +#, fuzzy +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 "" +"El uso de un puntero contado de referencia ofrece lo mejor de ambos mundos: " +"podemos reutilizar\n" +"la estructura de datos original, y no necesitamos clonar nodos sin cambios. " +"Sin embargo,\n" +"son menos ergonómicos de usar y significan que las estructuras de datos no " +"pueden ser\n" +"mudable." + +#: src\patterns/creational/fold.md:111 +#, fuzzy +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 "" +"Los iteradores tienen un método `doblar`, sin embargo, este dobla una " +"estructura de datos en una\n" +"valor, en lugar de en una nueva estructura de datos. El `mapa` de un " +"iterador es más como\n" +"este patrón de plegado." + +#: src\patterns/creational/fold.md:115 +#, fuzzy +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 "" +"En otros lenguajes, fold se usa generalmente en el sentido de los iteradores " +"de Rust,\n" +"en lugar de este patrón. Algunos lenguajes funcionales tienen poderosas " +"construcciones para\n" +"realizar mapas flexibles sobre estructuras de datos." + +#: src\patterns/creational/fold.md:119 +#, fuzzy +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 "" +"El patrón [visitante](../behavioural/visitor.md) está estrechamente " +"relacionado con el pliegue.\n" +"Comparten el concepto de recorrer una estructura de datos realizando una " +"operación sobre\n" +"cada nodo. Sin embargo, el visitante no crea una nueva estructura de datos " +"ni consume\n" +"el viejo." + +#: src\patterns/structural/intro.md:1 +#, fuzzy +msgid "# Structural Patterns" +msgstr "# Patrones Estructurales" + +#: src\patterns/structural/intro.md:3 +#, fuzzy +msgid "From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" +msgstr "De [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern):" + +#: src\patterns/structural/intro.md:5 +#, fuzzy +msgid "" +"> Design patterns that ease the design by identifying a simple way to " +"realize relationships\n" +"> among entities." +msgstr "" +"> Patrones de diseño que facilitan el diseño al identificar una forma " +"sencilla de realizar relaciones\n" +"> entre entidades." + +#: src\patterns/structural/compose-structs.md:1 +#, fuzzy +msgid "# Compose structs together for better borrowing" +msgstr "# Componer estructuras juntas para un mejor préstamo" + +#: src\patterns/structural/compose-structs.md:3 +#, fuzzy +msgid "TODO - this is not a very snappy name" +msgstr "TODO - este no es un nombre muy ágil" + +#: src\patterns/structural/compose-structs.md:7 +#, fuzzy +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 "" +"A veces, una estructura grande causará problemas con el verificador de " +"préstamos, aunque\n" +"los campos se pueden tomar prestados de forma independiente, a veces toda la " +"estructura termina siendo\n" +"utilizados de una sola vez, impidiendo otros usos. Una solución podría ser " +"descomponer la estructura\n" +"en varias estructuras más pequeñas. Luego componga estos juntos en el " +"original\n" +"estructura Luego, cada estructura se puede tomar prestada por separado y " +"tener más flexibilidad\n" +"comportamiento." + +#: src\patterns/structural/compose-structs.md:14 +#, fuzzy +msgid "" +"This will often lead to a better design in other ways: applying this design\n" +"pattern often reveals smaller units of functionality." +msgstr "" +"Esto a menudo conducirá a un mejor diseño de otras maneras: aplicar este " +"diseño\n" +"patrón a menudo revela unidades más pequeñas de funcionalidad." + +#: src\patterns/structural/compose-structs.md:19 +#, fuzzy +msgid "" +"Here is a contrived example of where the borrow checker foils us in our plan " +"to\n" +"use a struct:" +msgstr "" +"Aquí hay un ejemplo artificial de dónde el verificador de préstamos nos " +"frustra en nuestro plan para\n" +"usar una estructura:" + +#: 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 +#, fuzzy +msgid "" +"We can apply this design pattern and refactor `A` into two smaller structs, " +"thus\n" +"solving the borrow checking issue:" +msgstr "" +"Podemos aplicar este patrón de diseño y refactorizar `A` en dos estructuras " +"más pequeñas, por lo tanto\n" +"resolviendo el problema de verificación de préstamo:" + +#: 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 +#, fuzzy +msgid "TODO Why and where you should use the pattern" +msgstr "TODO Por qué y dónde deberías usar el patrón" + +#: src\patterns/structural/compose-structs.md:77 +#, fuzzy +msgid "Lets you work around limitations in the borrow checker." +msgstr "Le permite sortear las limitaciones del verificador de préstamos." + +#: src\patterns/structural/compose-structs.md:79 +#, fuzzy +msgid "Often produces a better design." +msgstr "A menudo produce un mejor diseño." + +#: src\patterns/structural/compose-structs.md:83 +#, fuzzy +msgid "Leads to more verbose code." +msgstr "Conduce a un código más detallado." + +#: src\patterns/structural/compose-structs.md:85 +#, fuzzy +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 "" +"A veces, las estructuras más pequeñas no son buenas abstracciones, por lo " +"que terminamos con\n" +"un diseño peor. Eso es probablemente un 'olor a código', lo que indica que " +"el programa\n" +"debe ser refactorizado de alguna manera." + +#: src\patterns/structural/compose-structs.md:91 +#, fuzzy +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 "" +"Este patrón no es necesario en los idiomas que no tienen un verificador de " +"préstamos, por lo que\n" +"en ese sentido es exclusivo de Rust. Sin embargo, hacer unidades más " +"pequeñas de funcionalidad\n" +"a menudo conduce a un código más limpio: un principio de software " +"ampliamente reconocido\n" +"ingeniería, independiente del idioma." + +#: src\patterns/structural/compose-structs.md:96 +#, fuzzy +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 "" +"Este patrón se basa en el verificador de préstamos de Rust para poder tomar " +"prestados campos.\n" +"independientemente unos de otros. En el ejemplo, el verificador de préstamos " +"sabe que `a.b`\n" +"y `a.c` son distintos y se pueden tomar prestados de forma independiente, no " +"intenta\n" +"toma prestada toda `a`, lo que haría que este patrón fuera inútil." + +#: src\patterns/structural/small-crates.md:1 +#, fuzzy +msgid "# Prefer small crates" +msgstr "# Preferir cajas pequeñas" + +#: src\patterns/structural/small-crates.md:5 +#, fuzzy +msgid "Prefer small crates that do one thing well." +msgstr "Prefiere cajas pequeñas que hacen una sola cosa bien." + +#: src\patterns/structural/small-crates.md:7 +#, fuzzy +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 "" +"Cargo y crates.io facilitan la adición de bibliotecas de terceros, mucho más " +"que\n" +"en decir C o C++. Además, dado que los paquetes en crates.io no se pueden " +"editar ni eliminar\n" +"después de la publicación, cualquier compilación que funcione ahora debería " +"continuar funcionando en el futuro.\n" +"Deberíamos aprovechar esta herramienta y usar dependencias más pequeñas y " +"detalladas." + +#: src\patterns/structural/small-crates.md:14 +#, fuzzy +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 "" +"- Las cajas pequeñas son más fáciles de entender y fomentan un código más " +"modular.\n" +"- Las cajas permiten reutilizar código entre proyectos.\n" +" Por ejemplo, la caja `url` se desarrolló como parte del motor del " +"navegador Servo,\n" +" pero desde entonces ha encontrado un amplio uso fuera del proyecto.\n" +"- Desde la unidad de compilación\n" +" de Rust es la caja, dividir un proyecto en varias cajas puede permitir más " +"de\n" +" el código que se construirá en paralelo." + +#: src\patterns/structural/small-crates.md:24 +#, fuzzy +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 "" +"- Esto puede conducir al \"infierno de la dependencia\", cuando un proyecto " +"depende de múltiples conflictos\n" +" versiones de una caja al mismo tiempo. Por ejemplo, la caja `url` tiene " +"ambas versiones\n" +" 1.0 y 0.5. Dado que la `Url` de `url:1.0` y la `Url` de `url:0.5` son\n" +" diferentes tipos, un cliente HTTP que usa `url:0.5` no aceptaría valores " +"`Url`\n" +" de un web scraper que usa `url:1.0`.\n" +"- Los paquetes en crates.io no están curados. Una caja puede estar mal " +"escrita, tener\n" +" documentación poco útil, o ser totalmente malicioso.\n" +"- Dos cajas pequeñas pueden estar menos optimizadas que una grande, ya que " +"el compilador\n" +" no realiza la optimización del tiempo de enlace (LTO) de forma " +"predeterminada." + +#: src\patterns/structural/small-crates.md:36 +#, fuzzy +msgid "" +"The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides " +"functions\n" +"for converting `&T` to `&[T]`." +msgstr "" +"El cajón [`ref_slice`](https://crates.io/crates/ref_slice) proporciona " +"funciones\n" +"para convertir `&T` a `&[T]`." + +#: src\patterns/structural/small-crates.md:39 +#, fuzzy +msgid "" +"The [`url`](https://crates.io/crates/url) crate provides tools for working " +"with\n" +"URLs." +msgstr "" +"El cajón [`url`](https://crates.io/crates/url) proporciona herramientas para " +"trabajar con\n" +"URL." + +#: src\patterns/structural/small-crates.md:42 +#, fuzzy +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 "" +"El cajón [`num_cpus`](https://crates.io/crates/num_cpus) proporciona una " +"función para\n" +"consultar el número de CPU en una máquina." + +#: src\patterns/structural/small-crates.md:47 +#, fuzzy +msgid "- [crates.io: The Rust community crate host](https://crates.io/)" +msgstr "" +"- [crates.io: El host de cajas de la comunidad de Rust](https://crates.io/)" + +#: src\patterns/structural/unsafe-mods.md:1 +#, fuzzy +msgid "# Contain unsafety in small modules" +msgstr "# Contener la inseguridad en pequeños módulos" + +#: src\patterns/structural/unsafe-mods.md:5 +#, fuzzy +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 "" +"Si tiene un código \"inseguro\", cree el módulo más pequeño posible que " +"pueda mantener\n" +"las invariantes necesarias para construir una interfaz segura mínima sobre " +"la inseguridad. Empotrar\n" +"esto en un módulo más grande que contiene solo código seguro y presenta un " +"diseño ergonómico\n" +"interfaz. Tenga en cuenta que el módulo externo puede contener funciones y " +"métodos no seguros\n" +"que llaman directamente al código no seguro. Los usuarios pueden usar esto " +"para obtener beneficios de velocidad." + +#: src\patterns/structural/unsafe-mods.md:13 +#, fuzzy +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 "" +"- Esto restringe el código inseguro que debe ser auditado\n" +"- Escribir el módulo exterior es mucho más fácil, ya que puedes contar con " +"las garantías\n" +" del módulo interior" + +#: src\patterns/structural/unsafe-mods.md:19 +#, fuzzy +msgid "" +"- Sometimes, it may be hard to find a suitable interface.\n" +"- The abstraction may introduce inefficiencies." +msgstr "" +"- A veces, puede ser difícil encontrar una interfaz adecuada.\n" +"- La abstracción puede introducir ineficiencias." + +#: src\patterns/structural/unsafe-mods.md:24 +#, fuzzy +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 "" +"- La caja [`toolshed`](https://docs.rs/toolshed) contiene sus operaciones " +"inseguras\n" +" en submódulos, presentando una interfaz segura para los usuarios.\n" +"- La clase `String` de `std` es un contenedor sobre `Vec` con el " +"invariante agregado\n" +" que el contenido debe ser UTF-8 válido. Las operaciones en `String` " +"aseguran esto\n" +" comportamiento.\n" +" Sin embargo, los usuarios tienen la opción de usar un método \"no seguro\" " +"para crear una \"Cadena\",\n" +" en cuyo caso corresponde a ellos garantizar la vigencia de los contenidos." + +#: src\patterns/structural/unsafe-mods.md:34 +#, fuzzy +msgid "" +"- [Ralf Jung's Blog about invariants in unsafe " +"code](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" +msgstr "" +"- [Blog de Ralf Jung sobre invariantes en código no " +"seguro](https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html)" + +#: src\patterns/ffi/intro.md:1 +#, fuzzy +msgid "# FFI Patterns" +msgstr "# Patrones FFI" + +#: src\patterns/ffi/intro.md:3 +#, fuzzy +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 "" +"Escribir código FFI es un curso completo en sí mismo.\n" +"Sin embargo, aquí hay varios modismos que pueden actuar como indicadores y " +"evitar trampas.\n" +"para usuarios inexpertos de Rust inseguro." + +#: src\patterns/ffi/intro.md:7 +#, fuzzy +msgid "This section contains design patterns that may be useful when doing FFI." +msgstr "" +"Esta sección contiene patrones de diseño que pueden ser útiles al hacer FFI." + +#: src\patterns/ffi/intro.md:9 +#, fuzzy +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 "" +"1. Diseño de [API basada en objetos] (./export.md) que tiene buenas " +"características de seguridad de memoria,\n" +" y un límite limpio de lo que es seguro y lo que es inseguro\n" +"\n" +"2. [Consolidación de tipos en envoltorios] (./wrappers.md) - agrupa varios " +"tipos de Rust\n" +" juntos en un \"objeto\" opaco" + +#: src\patterns/ffi/export.md:1 +#, fuzzy +msgid "# Object-Based APIs" +msgstr "# API basadas en objetos" + +#: src\patterns/ffi/export.md:5 +#, fuzzy +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 "" +"Al diseñar API en Rust que están expuestas a otros lenguajes, hay algunos\n" +"principios de diseño importantes que son contrarios al diseño normal de la " +"API de Rust:" + +#: src\patterns/ffi/export.md:8 +#, fuzzy +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 "" +"1. Todos los tipos encapsulados deben ser _propiedad_ de Rust, " +"_administrados_ por el usuario,\n" +" y _opaco_.\n" +"2. Todos los tipos de datos transaccionales deben ser _propiedad_ del " +"usuario y _transparentes_.\n" +"3. Todo el comportamiento de la biblioteca debe ser funciones que actúen " +"sobre tipos encapsulados.\n" +"4. Todo el comportamiento de la biblioteca debe encapsularse en tipos que no " +"se basen en la estructura,\n" +" pero _procedencia/tiempo de vida_." + +#: src\patterns/ffi/export.md:17 +#, fuzzy +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 "" +"Rust tiene soporte FFI integrado para otros idiomas.\n" +"Lo hace al proporcionar una forma para que los autores de cajas proporcionen " +"API compatibles con C\n" +"a través de diferentes ABI (aunque eso no es importante para esta práctica)." + +#: src\patterns/ffi/export.md:21 +#, fuzzy +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 "" +"Rust FFI bien diseñado sigue los principios de diseño de C API, al tiempo " +"que compromete la\n" +"diseño en Rust lo menos posible. Hay tres objetivos con cualquier API " +"extranjera:" + +#: src\patterns/ffi/export.md:24 +#, fuzzy +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 "" +"1. Facilite su uso en el idioma de destino.\n" +"2. Evite que la API dicte inseguridad interna en el lado de Rust tanto como " +"sea posible.\n" +"3. Mantenga el potencial de inseguridad de la memoria y el \"comportamiento " +"indefinido\" de Rust como pequeño\n" +" como sea posible." + +#: src\patterns/ffi/export.md:29 +#, fuzzy +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 "" +"El código Rust debe confiar en la seguridad de la memoria del idioma " +"extranjero más allá de cierto\n" +"punto. Sin embargo, cada fragmento de código \"inseguro\" en el lado de Rust " +"es una oportunidad para\n" +"errores, o para exacerbar el \"comportamiento indefinido\"." + +#: src\patterns/ffi/export.md:33 +#, fuzzy +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 "" +"Por ejemplo, si la procedencia de un puntero es incorrecta, eso puede ser un " +"error de segmentación debido a\n" +"acceso a memoria inválido. Pero si es manipulado por un código no seguro, " +"podría volverse\n" +"corrupción del montón en toda regla." + +#: src\patterns/ffi/export.md:37 +#, fuzzy +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 "" +"El diseño de la API basada en objetos permite escribir correcciones que " +"tienen buena seguridad de memoria\n" +"características, y un límite claro de lo que es seguro y lo que es " +"\"inseguro\"." + +#: src\patterns/ffi/export.md:42 +#, fuzzy +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 "" +"El estándar POSIX define la API para acceder a una base de datos en archivo, " +"conocida como " +"[DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h) " +".\n" +"Es un excelente ejemplo de una API \"basada en objetos\"." + +#: src\patterns/ffi/export.md:45 +#, fuzzy +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 "" +"Aquí está la definición en C, que con suerte debería ser fácil de leer para " +"aquellos\n" +"involucrados en FFI. El comentario a continuación debería ayudar a " +"explicarlo para aquellos que\n" +"perder las sutilezas." + +#: 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 +#, fuzzy +msgid "This API defines two types: `DBM` and `datum`." +msgstr "Esta API define dos tipos: `DBM` y `datum`." + +#: src\patterns/ffi/export.md:66 +#, fuzzy +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 "" +"El tipo `DBM` se denominó tipo \"encapsulado\" anteriormente.\n" +"Está diseñado para contener el estado interno y actúa como un punto de " +"entrada para el\n" +"comportamiento de la biblioteca." + +#: src\patterns/ffi/export.md:70 +#, fuzzy +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 "" +"Es completamente opaco para el usuario, que no puede crear un 'DBM' por sí " +"mismo ya que\n" +"no saben su tamaño o diseño. En su lugar, deben llamar a `dbm_open`, y eso\n" +"solo les da _un puntero a uno_." + +#: src\patterns/ffi/export.md:74 +#, fuzzy +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 "" +"Esto significa que todos los 'DBM' son \"propiedad\" de la biblioteca en el " +"sentido de Rust.\n" +"El estado interno de tamaño desconocido se mantiene en la memoria controlada " +"por la biblioteca,\n" +"no el usuario. El usuario solo puede gestionar su ciclo de vida con `abrir` " +"y `cerrar`,\n" +"y realizar operaciones en él con las otras funciones." + +#: src\patterns/ffi/export.md:79 +#, fuzzy +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 "" +"El tipo `datum` se denominó tipo \"transaccional\" anteriormente.\n" +"Está diseñado para facilitar el intercambio de información entre la " +"biblioteca y\n" +"su usuario." + +#: src\patterns/ffi/export.md:83 +#, fuzzy +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 "" +"La base de datos está diseñada para almacenar \"datos no estructurados\", " +"sin longitud predefinida\n" +"o significado. Como resultado, el `dato` es el equivalente en C de una " +"rebanada de Rust: un montón\n" +"de bytes, y un recuento de cuántos hay. La principal diferencia es que hay\n" +"sin información de tipo, que es lo que indica `void`." + +#: src\patterns/ffi/export.md:88 +#, fuzzy +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 "" +"Tenga en cuenta que este encabezado está escrito desde el punto de vista de " +"la biblioteca.\n" +"Es probable que el usuario tenga algún tipo que esté usando, que tenga un " +"tamaño conocido.\n" +"Pero a la biblioteca no le importa, y según las reglas de conversión de C, " +"cualquier tipo detrás de un\n" +"el puntero se puede convertir en `void`." + +#: src\patterns/ffi/export.md:93 +#, fuzzy +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 "" +"Como se señaló anteriormente, este tipo es _transparente_ para el usuario. " +"Pero también, este tipo es\n" +"_propiedad_ del usuario.\n" +"Esto tiene ramificaciones sutiles, debido a ese puntero en su interior.\n" +"La pregunta es, ¿quién posee la memoria a la que apunta el puntero?" + +#: src\patterns/ffi/export.md:98 +#, fuzzy +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 "" +"La respuesta para la mejor seguridad de la memoria es \"el usuario\".\n" +"Pero en casos como recuperar un valor, el usuario no sabe cómo asignar\n" +"correctamente (ya que no saben cuánto tiempo es el valor). En este caso, la " +"biblioteca.\n" +"Se espera que el código use el montón al que el usuario tiene acceso, como " +"la biblioteca C.\n" +"`malloc` y `free` -- y luego _transferir propiedad_ en el sentido de Rust." + +#: src\patterns/ffi/export.md:104 +#, fuzzy +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 "" +"Todo esto puede parecer especulativo, pero esto es lo que significa un " +"puntero en C.\n" +"Significa lo mismo que Rust: \"vida útil definida por el usuario\".\n" +"El usuario de la biblioteca necesita leer la documentación para utilizarla " +"correctamente.\n" +"Dicho esto, hay algunas decisiones que tienen menos o mayores consecuencias " +"si los usuarios\n" +"hazlo mal Minimizarlos es de lo que se trata esta mejor práctica, y la " +"clave\n" +"es _transferir la propiedad de todo lo que es transparente_." + +#: src\patterns/ffi/export.md:113 +#, fuzzy +msgid "" +"This minimizes the number of memory safety guarantees the user must uphold " +"to a\n" +"relatively small number:" +msgstr "" +"Esto minimiza el número de garantías de seguridad de la memoria que el " +"usuario debe mantener a un nivel\n" +"número relativamente pequeño:" + +#: src\patterns/ffi/export.md:116 +#, fuzzy +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 "" +"1. No llame a ninguna función con un puntero no devuelto por `dbm_open` " +"(inválido\n" +" acceso o corrupción).\n" +"2. No llame a ninguna función en un puntero después de cerrar (usar después " +"de liberar).\n" +"3. El `dptr` en cualquier `datum` debe ser `NULL`, o apuntar a una porción " +"válida de memoria\n" +" en la longitud anunciada." + +#: src\patterns/ffi/export.md:122 +#, fuzzy +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 "" +"Además, evita muchos problemas de procedencia de punteros.\n" +"Para entender por qué, consideremos una alternativa con cierta profundidad: " +"iteración clave." + +#: src\patterns/ffi/export.md:125 +#, fuzzy +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 "" +"Rust es bien conocido por sus iteradores.\n" +"Al implementar uno, el programador crea un tipo separado con una vida útil " +"limitada\n" +"a su propietario, e implementa el rasgo `Iterator`." + +#: src\patterns/ffi/export.md:129 +#, fuzzy +msgid "Here is how iteration would be done in Rust for `DBM`:" +msgstr "Así es como se haría la iteración en Rust para `DBM`:" + +#: 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 +#, fuzzy +msgid "" +"This is clean, idiomatic, and safe. thanks to Rust's guarantees.\n" +"However, consider what a straightforward API translation would look like:" +msgstr "" +"Esto es limpio, idiomático y seguro. gracias a las garantías de Rust.\n" +"Sin embargo, considere cómo se vería una traducción de API sencilla:" + +#: 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 +#, fuzzy +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 "" +"Esta API pierde una pieza clave de información: la vida útil del iterador no " +"debe\n" +"exceda la vida útil del objeto `Dbm` que lo posee. Un usuario de la " +"biblioteca podría\n" +"úselo de una manera que haga que el iterador sobreviva a los datos en los " +"que está iterando,\n" +"resultando en la lectura de la memoria no inicializada." + +#: src\patterns/ffi/export.md:173 +#, fuzzy +msgid "" +"This example written in C contains a bug that will be explained afterwards:" +msgstr "" +"Este ejemplo escrito en C contiene un error que se explicará más adelante:" + +#: 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 +#, fuzzy +msgid "" +"This bug is a classic. Here's what happens when the iterator returns the\n" +"end-of-iteration marker:" +msgstr "" +"Este error es un clásico. Esto es lo que sucede cuando el iterador devuelve " +"el\n" +"marcador de fin de iteración:" + +#: src\patterns/ffi/export.md:205 +#, fuzzy +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 "" +"1. La condición del bucle establece `l` en cero y entra en el bucle porque " +"`0 >= 0`.\n" +"2. La longitud se incrementa, en este caso por cero.\n" +"3. La declaración if es verdadera, por lo que la base de datos está cerrada. " +"debe haber un descanso\n" +" declaración aquí.\n" +"4. La condición de bucle se ejecuta de nuevo, provocando una llamada " +"`siguiente` en el objeto cerrado." + +#: src\patterns/ffi/export.md:211 +#, fuzzy +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 "" +"¿La peor parte de este error?\n" +"Si la implementación de Rust fue cuidadosa, ¡este código funcionará la mayor " +"parte del tiempo!\n" +"Si la memoria para el objeto `Dbm` no se reutiliza de inmediato, una " +"verificación interna\n" +"es casi seguro que fallará, lo que hará que el iterador devuelva un `-1` que " +"indica\n" +"un error. Pero en ocasiones, provocará un fallo de segmentación, o peor " +"aún,\n" +"Corrupción de memoria sin sentido!" + +#: src\patterns/ffi/export.md:218 +#, fuzzy +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 "" +"Rust no puede evitar nada de esto.\n" +"Desde su perspectiva, puso esos objetos en su montón, les devolvió " +"punteros,\n" +"y cedieron el control de sus vidas. El código C simplemente debe \"jugar " +"bien\"." + +#: src\patterns/ffi/export.md:222 +#, fuzzy +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 "" +"El programador debe leer y comprender la documentación de la API.\n" +"Mientras que algunos consideran que está a la par del curso en C, un buen " +"diseño de API puede mitigar\n" +"este riesgo La API POSIX para `DBM` hizo esto al _consolidar la propiedad_ " +"de\n" +"el iterador con su padre:" + +#: 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 +#, fuzzy +msgid "" +"Thus, all the lifetimes were bound together, and such unsafety was prevented." +msgstr "" +"Por lo tanto, todas las vidas estaban unidas y se previno tal inseguridad." + +#: src\patterns/ffi/export.md:236 +#, fuzzy +msgid "" +"However, this design choice also has a number of drawbacks, which should be\n" +"considered as well." +msgstr "" +"Sin embargo, esta elección de diseño también tiene una serie de " +"inconvenientes, que deben ser\n" +"considerado también." + +#: src\patterns/ffi/export.md:239 +#, fuzzy +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 "" +"Primero, la propia API se vuelve menos expresiva.\n" +"Con POSIX DBM, solo hay un iterador por objeto y cada llamada cambia\n" +"su estado Esto es mucho más restrictivo que los iteradores en casi cualquier " +"idioma,\n" +"aunque sea seguro. Tal vez con otros objetos relacionados, cuyas vidas son\n" +"menos jerárquica, esta limitación es más costosa que la seguridad." + +#: src\patterns/ffi/export.md:245 +#, fuzzy +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 "" +"Segundo, dependiendo de las relaciones de las partes de la API, un esfuerzo " +"de diseño significativo\n" +"puede estar implicado. Muchos de los puntos de diseño más fáciles tienen " +"otros patrones asociados\n" +"con ellos:" + +#: src\patterns/ffi/export.md:249 +#, fuzzy +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 "" +"- [Consolidación de tipos de contenedor] (./wrappers.md) agrupa varios tipos " +"de Rust juntos\n" +" en un \"objeto\" opaco\n" +"\n" +"- [FFI Error Passing](../../idioms/ffi/errors.md) explica el manejo de " +"errores con enteros\n" +" códigos y valores de retorno de centinela (como punteros `NULL`)\n" +"\n" +"- [Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) permite " +"aceptar\n" +" cadenas con código inseguro mínimo, y es más fácil hacerlo bien que\n" +" [Pasar cadenas a FFI](../../idioms/ffi/passing-strings.md)" + +#: src\patterns/ffi/export.md:259 +#, fuzzy +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 "" +"Sin embargo, no todas las API se pueden hacer de esta manera.\n" +"Depende del mejor juicio del programador quién es su audiencia." + +#: src\patterns/ffi/wrappers.md:1 +#, fuzzy +msgid "# Type Consolidation into Wrappers" +msgstr "# Escriba la consolidación en contenedores" + +#: src\patterns/ffi/wrappers.md:5 +#, fuzzy +msgid "" +"This pattern is designed to allow gracefully handling multiple related " +"types,\n" +"while minimizing the surface area for memory unsafety." +msgstr "" +"Este patrón está diseñado para permitir el manejo elegante de múltiples " +"tipos relacionados,\n" +"mientras minimiza el área de superficie para la inseguridad de la memoria." + +#: src\patterns/ffi/wrappers.md:8 +#, fuzzy +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 "" +"Una de las piedras angulares de las reglas de aliasing de Rust son las " +"vidas.\n" +"Esto asegura que muchos patrones de acceso entre tipos puedan ser seguros " +"para la memoria,\n" +"seguridad de carrera de datos incluida." + +#: src\patterns/ffi/wrappers.md:12 +#, fuzzy +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 "" +"Sin embargo, cuando los tipos de Rust se exportan a otros lenguajes, " +"generalmente se transforman\n" +"en punteros. En Rust, un puntero significa \"el usuario administra la vida " +"útil del pointee\".\n" +"Es su responsabilidad evitar la inseguridad de la memoria." + +#: src\patterns/ffi/wrappers.md:16 +#, fuzzy +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 "" +"Por lo tanto, se requiere cierto nivel de confianza en el código de usuario, " +"especialmente en torno al uso después de la liberación.\n" +"sobre el cual Rust no puede hacer nada. Sin embargo, algunos diseños de API " +"imponen mayores cargas\n" +"que otros en el código escrito en el otro idioma." + +#: src\patterns/ffi/wrappers.md:20 +#, fuzzy +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 "" +"La API de menor riesgo es el \"contenedor consolidado\", donde todas las " +"posibles interacciones\n" +"con un objeto se pliegan en un \"tipo contenedor\", mientras se mantiene " +"limpia la API de Rust." + +#: src\patterns/ffi/wrappers.md:25 +#, fuzzy +msgid "" +"To understand this, let us look at a classic example of an API to export: " +"iteration\n" +"through a collection." +msgstr "" +"Para entender esto, veamos un ejemplo clásico de una API para exportar: " +"iteración\n" +"a través de una colección." + +#: src\patterns/ffi/wrappers.md:28 +#, fuzzy +msgid "That API looks like this:" +msgstr "Esa API se ve así:" + +#: src\patterns/ffi/wrappers.md:30 +#, fuzzy +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 "" +"1. El iterador se inicializa con `first_key`.\n" +"2. Cada llamada a `next_key` hará avanzar el iterador.\n" +"3. Las llamadas a `next_key` si el iterador está al final no harán nada.\n" +"4. Como se señaló anteriormente, el iterador está \"envuelto\" en la " +"colección (a diferencia del nativo\n" +" API de óxido)." + +#: src\patterns/ffi/wrappers.md:36 +#, fuzzy +msgid "" +"If the iterator implements `nth()` efficiently, then it is possible to make " +"it\n" +"ephemeral to each function call:" +msgstr "" +"Si el iterador implementa `nth()` de manera eficiente, entonces es posible " +"hacerlo\n" +"efímero a cada llamada de función:" + +#: 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 +#, fuzzy +msgid "As a result, the wrapper is simple and contains no `unsafe` code." +msgstr "" +"Como resultado, el envoltorio es simple y no contiene código \"no seguro\"." + +#: src\patterns/ffi/wrappers.md:65 +#, fuzzy +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 "" +"Esto hace que las API sean más seguras de usar, evitando problemas con la " +"vida útil entre tipos.\n" +"Consulte [API basadas en objetos] (./export.md) para obtener más información " +"sobre las ventajas y desventajas\n" +"esto evita." + +#: src\patterns/ffi/wrappers.md:71 +#, fuzzy +msgid "" +"Often, wrapping types is quite difficult, and sometimes a Rust API " +"compromise\n" +"would make things easier." +msgstr "" +"A menudo, envolver tipos es bastante difícil y, a veces, un compromiso de la " +"API de Rust\n" +"facilitaría las cosas." + +#: src\patterns/ffi/wrappers.md:74 +#, fuzzy +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 "" +"Como ejemplo, considere un iterador que no implementa eficientemente " +"`nth()`.\n" +"Definitivamente valdría la pena poner una lógica especial para hacer que el " +"objeto maneje\n" +"iteración internamente, o para admitir un patrón de acceso diferente de " +"manera eficiente que\n" +"solo se utilizará la API de funciones externas." + +#: src\patterns/ffi/wrappers.md:79 +#, fuzzy +msgid "### Trying to Wrap Iterators (and Failing)" +msgstr "### Tratando de envolver iteradores (y fallando)" + +#: src\patterns/ffi/wrappers.md:81 +#, fuzzy +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 "" +"Para envolver cualquier tipo de iterador en la API correctamente, el " +"envoltorio tendría que\n" +"hacer lo que haría una versión C del código: borrar la vida útil del " +"iterador,\n" +"y administrarlo manualmente." + +#: src\patterns/ffi/wrappers.md:85 +#, fuzzy +msgid "Suffice it to say, this is _incredibly_ difficult." +msgstr "Baste decir que esto es _increíblemente_ difícil." + +#: src\patterns/ffi/wrappers.md:87 +#, fuzzy +msgid "Here is an illustration of just _one_ pitfall." +msgstr "Aquí hay una ilustración de solo _one_ escollo." + +#: src\patterns/ffi/wrappers.md:89 +#, fuzzy +msgid "A first version of `MySetWrapper` would look like this:" +msgstr "Una primera versión de `MySetWrapper` se vería así:" + +#: 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 +#, fuzzy +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 "" +"Con 'transmutar' que se usa para extender la vida útil y un puntero para " +"ocultarlo,\n" +"ya es feo. Pero se pone aún peor: _cualquier otra operación puede causar\n" +"Rust `comportamiento indefinido`_." + +#: src\patterns/ffi/wrappers.md:104 +#, fuzzy +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 "" +"Considere que `MySet` en el contenedor podría ser manipulado por otros\n" +"funciones durante la iteración, como almacenar un nuevo valor en la clave " +"que fue\n" +"iterando sobre. La API no desaconseja esto, y de hecho algunos C similares\n" +"las bibliotecas lo esperan." + +#: src\patterns/ffi/wrappers.md:109 +#, fuzzy +msgid "A simple implementation of `myset_store` would be:" +msgstr "Una implementación simple de `myset_store` sería:" + +#: 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 +#, fuzzy +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 "" +"Si el iterador existe cuando se llama a esta función, hemos violado una de " +"las reglas de Rust\n" +"reglas de alias. Según Rust, la referencia mutable en este bloque debe " +"tener\n" +"acceso _exclusivo_ al objeto. Si el iterador simplemente existe, no es " +"exclusivo,\n" +"¡así que tenemos un `comportamiento indefinido`!" + +#: src\patterns/ffi/wrappers.md:142 +#, fuzzy +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 "" +"Para evitar esto, debemos tener una forma de asegurar que la referencia " +"mutable sea realmente exclusiva.\n" +"Eso básicamente significa borrar la referencia compartida del iterador " +"mientras existe,\n" +"y luego reconstruirlo. En la mayoría de los casos, seguirá siendo menos " +"eficiente que\n" +"la versión C." + +#: src\patterns/ffi/wrappers.md:147 +#, fuzzy +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 "" +"Algunos pueden preguntarse: ¿cómo puede C hacer esto de manera más " +"eficiente?\n" +"La respuesta es que hace trampa. Las reglas de alias de Rust son el " +"problema, y C simplemente ignora\n" +"ellos por sus punteros. A cambio, es común ver código que se declara\n" +"en el manual como \"no seguro para subprocesos\" en algunas o todas las " +"circunstancias. De hecho,\n" +"la [biblioteca GNU " +"C](https://manpages.debian.org/buster/manpages/attributes.7.en.html)\n" +"tiene un léxico completo dedicado al comportamiento concurrente!" + +#: src\patterns/ffi/wrappers.md:154 +#, fuzzy +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 "" +"Rust prefiere que todo sea seguro para la memoria todo el tiempo, tanto por " +"seguridad como por\n" +"optimizaciones que el código C no puede lograr. Ser denegado el acceso a " +"ciertos accesos directos\n" +"es el precio que los programadores de Rust deben pagar." + +#: src\patterns/ffi/wrappers.md:158 +#, fuzzy +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 "" +"Para los programadores de C que se rascan la cabeza, el iterador necesita\n" +"no se leerá _durante_ este código causará la UB. La regla de exclusividad " +"también permite\n" +"optimizaciones del compilador que pueden causar observaciones inconsistentes " +"por parte del iterador\n" +"referencia compartida (por ejemplo, derrames de pilas o instrucciones de " +"reordenación para mayor eficiencia).\n" +"Estas observaciones pueden ocurrir _en cualquier momento después de_ que se " +"cree la referencia mutable." + +#: src\anti_patterns/index.md:1 +#, fuzzy +msgid "# Anti-patterns" +msgstr "# Anti-patrones" + +#: src\anti_patterns/index.md:3 +#, fuzzy +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 "" +"Un [antipatrón](https://en.wikipedia.org/wiki/Anti-pattern) es una solución " +"para\n" +"un \"problema recurrente que generalmente es ineficaz y corre el riesgo de " +"ser altamente\n" +"contraproducente\". Tan valioso como saber cómo resolver un problema, es\n" +"saber cómo _no_ resolverlo. Los antipatrones nos dan grandes contraejemplos " +"para\n" +"considerar en relación con los patrones de diseño. Los antipatrones no se " +"limitan al código.\n" +"Por ejemplo, un proceso también puede ser un antipatrón." + +#: src\anti_patterns/borrow_clone.md:1 +#, fuzzy +msgid "# Clone to satisfy the borrow checker" +msgstr "# Clonar para satisfacer el verificador de préstamo" + +#: src\anti_patterns/borrow_clone.md:5 +#, fuzzy +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 "" +"El verificador de préstamos evita que los usuarios de Rust desarrollen " +"código que de otro modo no sería seguro.\n" +"asegurando que: solo existe una referencia mutable, o potencialmente muchas " +"pero\n" +"todas las referencias inmutables existen. Si el código escrito no es fiel a " +"estos\n" +"condiciones, este antipatrón surge cuando el desarrollador resuelve el " +"compilador\n" +"error al clonar la variable." + +#: 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 +#, fuzzy +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 "" +"Es tentador, especialmente para los principiantes, usar este patrón para " +"resolver\n" +"Problemas confusos con el verificador de préstamos. Sin embargo, existen " +"graves\n" +"consecuencias. El uso de `.clone()` hace que se haga una copia de los datos. " +"Algún cambio\n" +"entre los dos no están sincronizados, como si dos variables completamente " +"separadas\n" +"existir." + +#: src\anti_patterns/borrow_clone.md:38 +#, fuzzy +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 "" +"Hay casos especiales: `Rc` está diseñado para manejar clones de forma " +"inteligente.\n" +"Administra internamente exactamente una copia de los datos, y clonarlos " +"solo\n" +"clonar la referencia." + +#: src\anti_patterns/borrow_clone.md:42 +#, fuzzy +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 "" +"También existe `Arc` que proporciona la propiedad compartida de un valor " +"de tipo T\n" +"que se asigna en el montón. Invocar `.clone()` en `Arc` produce un nuevo " +"`Arc`\n" +"instancia, que apunta a la misma asignación en el montón que la fuente " +"`Arc`,\n" +"mientras aumenta un recuento de referencia." + +#: src\anti_patterns/borrow_clone.md:47 +#, fuzzy +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 "" +"En general, los clones deben ser deliberados, con pleno conocimiento de los\n" +"consecuencias. Si se usa un clon para hacer que desaparezca un error del " +"comprobador de préstamo,\n" +"esa es una buena indicación de que este antipatrón puede estar en uso." + +#: src\anti_patterns/borrow_clone.md:51 +#, fuzzy +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 "" +"Aunque `.clone()` es una indicación de un mal patrón, a veces\n" +"**está bien escribir código ineficiente**, en casos como cuando:" + +#: src\anti_patterns/borrow_clone.md:54 +#, fuzzy +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 "" +"- el desarrollador aún es nuevo en la propiedad\n" +"- el código no tiene grandes limitaciones de velocidad o memoria\n" +" (como proyectos de hackathon o prototipos)\n" +"- satisfacer el verificador de préstamos es realmente complicado, y " +"prefieres\n" +" optimizar la legibilidad sobre el rendimiento" + +#: src\anti_patterns/borrow_clone.md:60 +#, fuzzy +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 "" +"Si se sospecha de un clon innecesario, el [capítulo de Rust Book sobre " +"propiedad] (https://doc.rust-lang.org/book/ownership.html)\n" +"debe entenderse completamente antes de evaluar si el clon es necesario o no." + +#: src\anti_patterns/borrow_clone.md:63 +#, fuzzy +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 "" +"También asegúrese de ejecutar siempre `cargo clippy` en su proyecto, que " +"detectará algunos\n" +"casos en los que `.clone()` no es necesario, como " +"[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) o " +"[4](https://rust-lang.github.io/rust-clippy/master " +"/index.html#clone_double_ref)." + +#: src\anti_patterns/borrow_clone.md:70 +#, fuzzy +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 "" +"- [`mem::{take(_), replace(_)}` para mantener los valores propios en las " +"enumeraciones modificadas](../idioms/mem-replace.md)\n" +"- [Documentación `Rc`, que maneja .clone() " +"inteligentemente](http://doc.rust-lang.org/std/rc/)\n" +"- [Documentación de `Arc`, un puntero de recuento de referencia seguro " +"para subprocesos] (https://doc.rust-lang.org/std/sync/struct.Arc.html)\n" +"- [Trucos con propiedad en " +"Rust](https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html)" + +#: src\anti_patterns/deny-warnings.md:1 +#, fuzzy +msgid "# `#![deny(warnings)]`" +msgstr "# `#![negar(advertencias)]`" + +#: src\anti_patterns/deny-warnings.md:5 +#, fuzzy +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 "" +"Un autor de cajas bien intencionado quiere asegurarse de que su código se " +"construya sin\n" +"advertencias Así que anotan su raíz de caja con lo siguiente:" + +#: 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 +#, fuzzy +msgid "It is short and will stop the build if anything is amiss." +msgstr "Es breve y detendrá la compilación si algo anda mal." + +#: src\anti_patterns/deny-warnings.md:20 +#, fuzzy +msgid "## Drawbacks" +msgstr "## Inconvenientes" + +#: src\anti_patterns/deny-warnings.md:22 +#, fuzzy +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 "" +"Al no permitir que el compilador construya con advertencias, el autor de un " +"cajón opta por no participar\n" +"La famosa estabilidad de Rust. A veces, las nuevas características o las " +"antiguas características incorrectas necesitan un cambio.\n" +"en cómo se hacen las cosas, así se escriben hilachas que `advierten` para " +"cierta gracia\n" +"antes de pasar a `denegar`." + +#: src\anti_patterns/deny-warnings.md:27 +#, fuzzy +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 "" +"Por ejemplo, se descubrió que un tipo podía tener dos `impl`s con el mismo\n" +"método. Esto se consideró una mala idea, pero para que la transición sea " +"fluida,\n" +"el lint `overlapping-inherent-impls` se introdujo para dar una advertencia a " +"aquellos\n" +"tropezando con este hecho, antes de que se convierta en un error grave en " +"una versión futura." + +#: src\anti_patterns/deny-warnings.md:32 +#, fuzzy +msgid "" +"Also sometimes APIs get deprecated, so their use will emit a warning where\n" +"before there was none." +msgstr "" +"Además, a veces las API quedan obsoletas, por lo que su uso emitirá una " +"advertencia donde\n" +"antes no había ninguno." + +#: src\anti_patterns/deny-warnings.md:35 +#, fuzzy +msgid "" +"All this conspires to potentially break the build whenever something changes." +msgstr "" +"Todo esto conspira para potencialmente romper la compilación cada vez que " +"algo cambia." + +#: src\anti_patterns/deny-warnings.md:37 +#, fuzzy +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 "" +"Además, las cajas que suministren pelusas adicionales (por ejemplo, " +"[rust-clippy]) no pueden\n" +"ya no se utilizará a menos que se elimine la anotación. Esto se mitiga con\n" +"[--cap-pelusas]. El argumento de la línea de comando `--cap-lints=warn` " +"convierte todo `deny`\n" +"lint errores en advertencias." + +#: src\anti_patterns/deny-warnings.md:42 +#: src\functional/generics-type-classes.md:227 +#, fuzzy +msgid "## Alternatives" +msgstr "## Alternativas" + +#: src\anti_patterns/deny-warnings.md:44 +#, fuzzy +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 "" +"Hay dos formas de abordar este problema: primero, podemos desacoplar la " +"compilación\n" +"configuración del código, y segundo, podemos nombrar las pelusas que " +"queremos denegar\n" +"explícitamente." + +#: src\anti_patterns/deny-warnings.md:48 +#, fuzzy +msgid "The following command line will build with all warnings set to `deny`:" +msgstr "" +"La siguiente línea de comando se construirá con todas las advertencias " +"configuradas en \"denegar\":" + +#: src\anti_patterns/deny-warnings.md:50 +#, fuzzy +msgid "`RUSTFLAGS=\"-D warnings\" cargo build`" +msgstr "`RUSTFLAGS=\"-D advertencias\" construcción de carga`" + +#: src\anti_patterns/deny-warnings.md:52 +#, fuzzy +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 "" +"Esto lo puede hacer cualquier desarrollador individual (o se puede " +"configurar en una herramienta de CI como\n" +"Travis, pero recuerda que esto puede romper la compilación cuando algo " +"cambia)\n" +"sin requerir un cambio en el código." + +#: src\anti_patterns/deny-warnings.md:56 +#, fuzzy +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 "" +"Alternativamente, podemos especificar los lints que queremos `denegar` en el " +"código.\n" +"Aquí hay una lista de pelusas de advertencia que (con suerte) son seguras de " +"negar (a partir de Rustc 1.48.0):" + +#: 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 +#, fuzzy +msgid "In addition, the following `allow`ed lints may be a good idea to `deny`:" +msgstr "" +"Además, las siguientes pelusas \"permitidas\" pueden ser una buena idea para " +"\"denegar\":" + +#: 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 +#, fuzzy +msgid "Some may also want to add `missing-copy-implementations` to their list." +msgstr "" +"Algunos también pueden querer agregar \"implementaciones de copias " +"faltantes\" a su lista." + +#: src\anti_patterns/deny-warnings.md:93 +#, fuzzy +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 "" +"Tenga en cuenta que no agregamos explícitamente la pelusa `obsoleta`, ya que " +"es bastante\n" +"seguro de que habrá más API obsoletas en el futuro." + +#: src\anti_patterns/deny-warnings.md:98 +#, fuzzy +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 "" +"- [Una colección de todas las pelusas cortadas] " +"(https://rust-lang.github.io/rust-clippy/master)\n" +"- Documentación de [atributo en desuso]\n" +"- Escriba `rustc -W help` para obtener una lista de pelusas en su sistema. " +"También escriba\n" +" `rustc --help` para una lista general de opciones\n" +"- [rust-clippy] es una colección de pelusas para mejorar el código de Rust" + +#: src\anti_patterns/deref.md:1 +#, fuzzy +msgid "# `Deref` polymorphism" +msgstr "# Polimorfismo `Deref`" + +#: src\anti_patterns/deref.md:5 +#, fuzzy +msgid "" +"Misuse the `Deref` trait to emulate inheritance between structs, and thus " +"reuse\n" +"methods." +msgstr "" +"Usar incorrectamente el rasgo `Deref` para emular la herencia entre " +"estructuras y, por lo tanto, reutilizar\n" +"métodos." + +#: src\anti_patterns/deref.md:10 +#, fuzzy +msgid "" +"Sometimes we want to emulate the following common pattern from OO languages " +"such\n" +"as Java:" +msgstr "" +"A veces queremos emular el siguiente patrón común de los lenguajes OO como\n" +"como Java:" + +#: 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 +#, fuzzy +msgid "We can use the deref polymorphism anti-pattern to do so:" +msgstr "Podemos usar el antipatrón de polimorfismo deref para hacerlo:" + +#: 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 +#, fuzzy +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 "" +"No hay herencia de estructuras en Rust. En su lugar, usamos composición e " +"incluimos\n" +"una instancia de `Foo` en `Bar` (dado que el campo es un valor, se almacena " +"en línea,\n" +"entonces, si hubiera campos, tendrían el mismo diseño en la memoria que " +"Java\n" +"versión (probablemente, debería usar `#[repr(C)]` si quiere estar seguro))." + +#: src\anti_patterns/deref.md:61 +#, fuzzy +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 "" +"Para hacer que la llamada al método funcione, implementamos `Deref` para " +"`Bar` con `Foo`\n" +"como objetivo (devolviendo el campo `Foo` incrustado). Eso significa que " +"cuando nosotros\n" +"desreferenciar una `Bar` (por ejemplo, usando `*`) entonces obtendremos un " +"`Foo`. Eso es\n" +"bastante raro. La desreferenciación generalmente da una `T` de una " +"referencia a `T`, aquí\n" +"tienen dos tipos no relacionados. Sin embargo, dado que el operador punto " +"hace implícito\n" +"desreferenciación, significa que la llamada al método buscará métodos en " +"`Foo` como\n" +"así como `Bar`." + +#: src\anti_patterns/deref.md:71 +#, fuzzy +msgid "You save a little boilerplate, e.g.," +msgstr "Te ahorras un poco de texto repetitivo, por ejemplo," + +#: 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 +#, fuzzy +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 "" +"Lo más importante es que este es un idioma sorprendente: los futuros " +"programadores que lean esto en\n" +"el código no esperará que esto suceda. Eso es porque estamos haciendo un mal " +"uso de `Deref`\n" +"rasgo en lugar de usarlo según lo previsto (y documentado, etc.). también es " +"porque\n" +"el mecanismo aquí es completamente implícito." + +#: src\anti_patterns/deref.md:88 +#, fuzzy +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 "" +"Este patrón no introduce subtipos entre `Foo` y `Bar` como\n" +"la herencia en Java o C++ sí. Además, los rasgos implementados por `Foo` " +"son\n" +"no se implementa automáticamente para `Bar`, por lo que este patrón " +"interactúa mal con\n" +"verificación de límites y, por lo tanto, programación genérica." + +#: src\anti_patterns/deref.md:93 +#, fuzzy +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 "" +"El uso de este patrón proporciona una semántica sutilmente diferente de la " +"mayoría de los lenguajes OO con\n" +"en lo que respecta a 'uno mismo'. Por lo general, sigue siendo una " +"referencia a la subclase, con esto\n" +"patrón será la 'clase' donde se define el método." + +#: src\anti_patterns/deref.md:97 +#, fuzzy +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 "" +"Finalmente, este patrón solo admite herencia única y no tiene noción de\n" +"interfaces, privacidad basada en clases u otras características relacionadas " +"con la herencia. Por lo que\n" +"brinda una experiencia que sorprenderá sutilmente a los programadores " +"acostumbrados a Java\n" +"herencia, etc" + +#: src\anti_patterns/deref.md:104 +#, fuzzy +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 "" +"No hay una buena alternativa. Dependiendo de las circunstancias exactas, " +"podría\n" +"sería mejor volver a implementar usando rasgos o escribir los métodos de " +"fachada para\n" +"enviar a `Foo` manualmente. Tenemos la intención de agregar un mecanismo " +"para la herencia.\n" +"similar a esto para Rust, pero es probable que pase algún tiempo antes de " +"que llegue\n" +"Roya estable. Ver estos " +"[blog](http://aturon.github.io/blog/2015/09/18/reuse/)\n" +"[publicaciones] " +"(http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/)\n" +"y este [problema de RFC] (https://github.com/rust-lang/rfcs/issues/349) para " +"obtener más detalles." + +#: src\anti_patterns/deref.md:112 +#, fuzzy +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 "" +"El rasgo `Deref` está diseñado para la implementación de tipos de punteros " +"personalizados.\n" +"La intención es que tomará un puntero a `T` a `T`, no convertir\n" +"entre diferentes tipos. Es una pena que esto no sea (probablemente no puede " +"ser)\n" +"reforzado por la definición de rasgo." + +#: src\anti_patterns/deref.md:117 +#, fuzzy +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 "" +"Rust intenta lograr un equilibrio cuidadoso entre los mecanismos explícitos " +"e implícitos,\n" +"favoreciendo conversiones explícitas entre tipos. Eliminación automática de " +"referencias en el punto\n" +"operador es un caso donde la ergonomía favorece fuertemente un mecanismo " +"implícito,\n" +"pero la intención es que esto se limite a grados de indirección, no\n" +"conversión entre tipos arbitrarios." + +#: src\anti_patterns/deref.md:125 +#, fuzzy +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 "" +"- [Las colecciones son modismos de punteros " +"inteligentes](../idioms/deref.md).\n" +"- Cajas de delegación para menos repetitivo como " +"[delegate](https://crates.io/crates/delegate)\n" +" o [embajador](https://crates.io/crates/ambassador)\n" +"- [Documentación para el rasgo " +"`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html)." + +#: src\functional/index.md:1 +#, fuzzy +msgid "# Functional Usage of Rust" +msgstr "# Uso funcional de Rust" + +#: src\functional/index.md:3 +#, fuzzy +msgid "" +"Rust is an imperative language, but it follows many\n" +"[functional " +"programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms." +msgstr "" +"Rust es un lenguaje imperativo, pero sigue muchos\n" +"[programación " +"funcional](https://en.wikipedia.org/wiki/Functional_programming) paradigmas." + +#: src\functional/index.md:6 +#, fuzzy +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 "" +"> En informática, la _programación funcional_ es un paradigma de " +"programación donde\n" +"> los programas se construyen aplicando y componiendo funciones.\n" +"> Es un paradigma de programación declarativa en el que las definiciones de " +"funciones son\n" +"> árboles de expresiones que devuelven un valor, en lugar de una secuencia " +"de\n" +"> declaraciones imperativas que cambian el estado del programa." + +#: src\functional/paradigms.md:1 +#, fuzzy +msgid "# Programming paradigms" +msgstr "# Paradigmas de programación" + +#: src\functional/paradigms.md:3 +#, fuzzy +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 "" +"Uno de los mayores obstáculos para comprender los programas funcionales " +"cuando se trata de\n" +"desde un trasfondo imperativo es el cambio de pensamiento. programas " +"imperativos\n" +"describen **cómo** hacer algo, mientras que los programas declarativos " +"describen\n" +"**qué hacer. Sumemos los números del 1 al 10 para mostrar esto." + +#: src\functional/paradigms.md:8 +#, fuzzy +msgid "## Imperative" +msgstr "## Imperativo" + +#: 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 +#, fuzzy +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 "" +"Con los programas imperativos, tenemos que jugar al compilador para ver qué " +"está pasando.\n" +"Aquí, comenzamos con una `suma` de `0`.\n" +"A continuación, iteramos a través del rango de 1 a 10.\n" +"Cada vez que recorremos el bucle, sumamos el valor correspondiente en el " +"rango.\n" +"Luego lo imprimimos." + +#: src\functional/paradigms.md:24 +#, fuzzy +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 "" +"| `yo` | `suma` |\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 |" + +#: src\functional/paradigms.md:37 +#, fuzzy +msgid "" +"This is how most of us start out programming. We learn that a program is a " +"set\n" +"of steps." +msgstr "" +"Así es como la mayoría de nosotros empezamos a programar. Aprendemos que un " +"programa es un conjunto\n" +"de pasos" + +#: src\functional/paradigms.md:40 +#, fuzzy +msgid "## Declarative" +msgstr "## Declarativo" + +#: src\functional/paradigms.md:42 +msgid "" +"```rust\n" +"println!(\"{}\", (1..11).fold(0, |a, b| a + b));\n" +"```" +msgstr "" + +#: src\functional/paradigms.md:46 +#, fuzzy +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 "" +"¡Guau! ¡Esto es realmente diferente! ¿Que está pasando aqui?\n" +"Recuerde que con los programas declarativos estamos describiendo **qué** " +"hacer,\n" +"en lugar de **cómo** hacerlo. `fold` es una función que [compone] " +"(https://en.wikipedia.org/wiki/Function_composition)\n" +"funciones El nombre es una convención de Haskell." + +#: src\functional/paradigms.md:51 +#, fuzzy +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 "" +"Aquí, estamos componiendo funciones de suma (este cierre: `|a, b| a + b`)\n" +"con un rango de 1 a 10. El `0` es el punto de partida, por lo que `a` es `0` " +"en\n" +"primero. `b` es el primer elemento del rango, `1`. `0 + 1 = 1` es el " +"resultado.\n" +"Así que ahora 'doblamos' de nuevo, con 'a = 1', 'b = 2' y así '1 + 2 = 3' es " +"el siguiente\n" +"resultado. Este proceso continúa hasta que llegamos al último elemento del " +"rango,\n" +"`10`." + +#: src\functional/paradigms.md:58 +#, fuzzy +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 "" +"| `a` | `b` | resultado |\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/generics-type-classes.md:1 +#, fuzzy +msgid "# Generics as Type Classes" +msgstr "# Genéricos como clases de tipos" + +#: src\functional/generics-type-classes.md:5 +#, fuzzy +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 "" +"El sistema de tipos de Rust está diseñado más como lenguajes funcionales " +"(como Haskell)\n" +"en lugar de lenguajes imperativos (como Java y C++). Como resultado, Rust " +"puede convertir\n" +"muchos tipos de problemas de programación en problemas de \"tipado " +"estático\". Este es uno\n" +"de las mayores ganancias de elegir un lenguaje funcional, y es fundamental " +"para muchos\n" +"de las garantías de tiempo de compilación de Rust." + +#: src\functional/generics-type-classes.md:11 +#, fuzzy +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 "" +"Una parte clave de esta idea es la forma en que funcionan los tipos " +"genéricos. En C++ y Java, por\n" +"Por ejemplo, los tipos genéricos son una construcción de metaprogramación " +"para el compilador.\n" +"`vector` y `vector` en C++ son solo dos copias diferentes del\n" +"mismo código repetitivo para un tipo `vector` (conocido como `plantilla`) " +"con dos\n" +"diferentes tipos rellenados." + +#: src\functional/generics-type-classes.md:17 +#, fuzzy +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 "" +"En Rust, un parámetro de tipo genérico crea lo que se conoce en lenguajes " +"funcionales\n" +"como una \"restricción de clase de tipo\", y cada parámetro diferente " +"completado por un extremo\n" +"el usuario _realmente cambia el tipo_. En otras palabras, `Vec` y " +"`Vec`\n" +"_son dos tipos diferentes_, que son reconocidos como distintos por todas las " +"partes del\n" +"sistema de tipos." + +#: src\functional/generics-type-classes.md:23 +#, fuzzy +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 "" +"Esto se llama **monomorfización**, donde se crean diferentes tipos a partir " +"de\n" +"Código **polimórfico**. Este comportamiento especial requiere bloques `impl` " +"para especificar\n" +"parámetros genéricos. Diferentes valores para el tipo genérico causan " +"diferentes tipos,\n" +"y diferentes tipos pueden tener diferentes bloques `impl`." + +#: src\functional/generics-type-classes.md:28 +#, fuzzy +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 "" +"En los lenguajes orientados a objetos, las clases pueden heredar el " +"comportamiento de sus padres.\n" +"Sin embargo, esto permite adjuntar no sólo un comportamiento adicional a\n" +"miembros particulares de una clase de tipo, pero también comportamiento " +"adicional." + +#: src\functional/generics-type-classes.md:32 +#, fuzzy +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 "" +"El equivalente más cercano es el polimorfismo en tiempo de ejecución en " +"Javascript y Python,\n" +"donde cualquier constructor puede agregar nuevos miembros a los objetos de " +"cualquier manera.\n" +"Sin embargo, a diferencia de esos lenguajes, todos los métodos adicionales " +"de Rust se pueden escribir\n" +"verificados cuando se usan, porque sus genéricos están definidos " +"estáticamente. Eso\n" +"los hace más utilizables sin dejar de ser seguros." + +#: src\functional/generics-type-classes.md:40 +#, fuzzy +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 "" +"Suponga que está diseñando un servidor de almacenamiento para una serie de " +"máquinas de laboratorio.\n" +"Debido al software involucrado, hay dos protocolos diferentes que necesita\n" +"para admitir: BOOTP (para arranque de red PXE) y NFS (para almacenamiento de " +"montaje remoto)." + +#: src\functional/generics-type-classes.md:44 +#, fuzzy +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 "" +"Su objetivo es tener un programa, escrito en Rust, que pueda manejar ambos\n" +"a ellos. Tendrá controladores de protocolo y escuchará ambos tipos de " +"solicitudes. El\n" +"La lógica de la aplicación principal permitirá que un administrador de " +"laboratorio configure el almacenamiento\n" +"y controles de seguridad para los archivos reales." + +#: src\functional/generics-type-classes.md:49 +#, fuzzy +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 "" +"Las solicitudes de archivos de las máquinas en el laboratorio contienen el " +"mismo\n" +"información, sin importar de qué protocolo provengan: un método de " +"autenticación,\n" +"y un nombre de archivo para recuperar. Una implementación sencilla se vería\n" +"algo como esto:" + +#: 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 +#, fuzzy +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 "" +"Este diseño podría funcionar lo suficientemente bien. Pero ahora supongamos " +"que necesita apoyo\n" +"agregando metadatos que eran _específicos del protocolo_. Por ejemplo, con " +"NFS, usted\n" +"quería determinar cuál era su punto de montaje para hacer cumplir\n" +"reglas de seguridad" + +#: src\functional/generics-type-classes.md:71 +#, fuzzy +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 "" +"La forma en que está diseñada la estructura actual deja la decisión del " +"protocolo hasta\n" +"tiempo de ejecución Eso significa cualquier método que se aplique a un " +"protocolo y no al otro.\n" +"requiere que el programador haga una verificación de tiempo de ejecución." + +#: src\functional/generics-type-classes.md:75 +#, fuzzy +msgid "Here is how getting an NFS mount point would look:" +msgstr "Así es como se vería obtener un punto de montaje NFS:" + +#: 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 +#, fuzzy +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 "" +"Cada llamador de `mount_point()` debe buscar `Ninguno` y escribir código " +"para manejar\n" +"él. Esto es cierto incluso si saben que solo se usan solicitudes NFS en un " +"determinado\n" +"ruta de código!" + +#: src\functional/generics-type-classes.md:99 +#, fuzzy +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 "" +"Sería mucho más óptimo causar un error en tiempo de compilación si los " +"diferentes\n" +"los tipos de solicitud estaban confundidos. Después de todo, la ruta " +"completa del código del usuario,\n" +"incluidas las funciones de la biblioteca que utilizan, sabrán si una " +"solicitud\n" +"es una solicitud NFS o una solicitud BOOTP." + +#: src\functional/generics-type-classes.md:104 +#, fuzzy +msgid "" +"In Rust, this is actually possible! The solution is to _add a generic type_ " +"in\n" +"order to split the API." +msgstr "" +"¡En Rust, esto es realmente posible! La solución es _agregar un tipo " +"genérico_ en\n" +"para dividir la API." + +#: src\functional/generics-type-classes.md:107 +#, fuzzy +msgid "Here is what that looks like:" +msgstr "Esto es lo que parece:" + +#: 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 +#, fuzzy +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 "" +"Obtendrían un error de sintaxis. El tipo `FileDownloadRequest` no\n" +"implementa `mount_point()`, solo lo hace el tipo `FileDownloadRequest`. " +"Y\n" +"eso lo crea el módulo NFS, ¡no el módulo BOOTP, por supuesto!" + +#: src\functional/generics-type-classes.md:212 +#, fuzzy +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 "" +"En primer lugar, permite eliminar la duplicación de campos que son comunes a " +"varios estados.\n" +"Al hacer que los campos no compartidos sean genéricos, se implementan una " +"vez." + +#: src\functional/generics-type-classes.md:215 +#, fuzzy +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 "" +"En segundo lugar, hace que los bloques `impl` sean más fáciles de leer, " +"porque están desglosados\n" +"por estado Los métodos comunes a todos los estados se escriben una vez en un " +"bloque y los métodos\n" +"exclusivos de un estado están en un bloque separado." + +#: src\functional/generics-type-classes.md:219 +#, fuzzy +msgid "" +"Both of these mean there are fewer lines of code, and they are better " +"organized." +msgstr "" +"Ambos significan que hay menos líneas de código y están mejor organizados." + +#: src\functional/generics-type-classes.md:223 +#, fuzzy +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 "" +"Esto actualmente aumenta el tamaño del binario, debido a la forma en que se " +"monomorfiza.\n" +"se implementa en el compilador. Esperemos que la implementación pueda\n" +"mejorar en el futuro." + +#: src\functional/generics-type-classes.md:229 +#, fuzzy +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 "" +"- Si un tipo parece necesitar una \"API dividida\" debido a la construcción " +"o parcial\n" +" inicialización, considere la\n" +" [Patrón de constructor] (../patterns/creational/builder.md) en su lugar.\n" +"\n" +"- Si la API entre tipos no cambia, solo cambia el comportamiento, entonces\n" +" el [Patrón de estrategia] (../patterns/behavioural/strategy.md) se usa " +"mejor\n" +" en cambio." + +#: src\functional/generics-type-classes.md:239 +#, fuzzy +msgid "This pattern is used throughout the standard library:" +msgstr "Este patrón se utiliza en toda la biblioteca estándar:" + +#: src\functional/generics-type-classes.md:241 +#, fuzzy +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 "" +"- `Vec` se puede convertir desde una cadena, a diferencia de cualquier " +"otro tipo de `Vec`.[^1]\n" +"- También se pueden convertir en un montón binario, pero solo si contienen " +"un tipo\n" +" que implementa el rasgo `Ord`.[^2]\n" +"- El método `to_string` se especializó para `Vaca` solo del tipo `str`.[^3]" + +#: src\functional/generics-type-classes.md:246 +#, fuzzy +msgid "It is also used by several popular crates to allow API flexibility:" +msgstr "" +"También lo utilizan varias cajas populares para permitir la flexibilidad de " +"la API:" + +#: src\functional/generics-type-classes.md:248 +#, fuzzy +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 "" +"- El ecosistema `embedded-hal` utilizado para dispositivos integrados hace " +"un uso extensivo de\n" +" este patrón Por ejemplo, permite verificar estáticamente la configuración " +"de\n" +" registros de dispositivos utilizados para controlar pines incrustados. " +"Cuando un pin se pone en un modo,\n" +" devuelve una estructura `Pin`, cuyo genérico determina las " +"funciones\n" +" utilizables en ese modo, que no están en el propio `Pin`. [^4]\n" +"\n" +"- La biblioteca de cliente HTTP 'hiper' usa esto para exponer API " +"enriquecidas para diferentes\n" +" solicitudes conectables. Los clientes con diferentes conectores tienen " +"diferentes métodos\n" +" en ellos, así como diferentes implementaciones de rasgos, mientras que un " +"conjunto básico de\n" +" Los métodos se aplican a cualquier conector. [^5]\n" +"\n" +"- El patrón de \"estado de tipo\", donde un objeto gana y pierde API en " +"función de un\n" +" estado interno o invariante: se implementa en Rust utilizando el mismo\n" +" concepto, y una técnica ligeramente diferente. [^6]" + +#: src\functional/generics-type-classes.md:263 +#, fuzzy +msgid "" +"See: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811)" +msgstr "" +"Ver: [impl From\\ for " +"Vec\\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811 " +")" + +#: src\functional/generics-type-classes.md:265 +#, fuzzy +msgid "" +"See: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354)" +msgstr "" +"Ver: [impl\\ From\\\\> for " +"BinaryHeap\\](https://doc.rust-lang.org/stable/src/alloc/collections " +"/binary_heap.rs.html#1345-1354)" + +#: src\functional/generics-type-classes.md:267 +#, fuzzy +msgid "" +"See: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240)" +msgstr "" +"Consulte: [impl\\<'\\_\\> ToString for Cow\\<'\\_, " +"str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235- 2240)" + +#: src\functional/generics-type-classes.md:269 +#, fuzzy +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 "" +"Ejemplo:\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/generics-type-classes.md:272 +#, fuzzy +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 "" +"Ver:\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/generics-type-classes.md:275 +#, fuzzy +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 "" +"Ver:\n" +"[El caso del patrón de estado " +"tipo](https://web.archive.org/web/20210325065112/https://www.novatec-gmbh.de/en/blog/the-case-for-the-typestate- " +"patrón-el-tipo-estado-patrón-en-sí/)\n" +"y\n" +"[Serie Rusty Typestate (una tesis " +"extensa)](https://web.archive.org/web/20210328164854/https://rustype.github.io/notes/notes/rust-typestate-series/rust-typestate-index " +")" + +#: src\functional/lenses.md:1 +#, fuzzy +msgid "# Lenses and Prisms" +msgstr "# Lentes y Prismas" + +#: src\functional/lenses.md:3 +#, fuzzy +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 "" +"Este es un concepto funcional puro que no se usa con frecuencia en Rust.\n" +"Sin embargo, explorar el concepto puede ser útil para entender otros\n" +"patrones en las API de Rust, como [visitantes] " +"(../patterns/behavioural/visitor.md).\n" +"También tienen casos de uso de nicho." + +#: src\functional/lenses.md:8 +#, fuzzy +msgid "## Lenses: Uniform Access Across Types" +msgstr "## Lentes: acceso uniforme en todos los tipos" + +#: src\functional/lenses.md:10 +#, fuzzy +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 "" +"Una lente es un concepto de los lenguajes de programación funcional que " +"permite\n" +"acceder a partes de un tipo de datos de forma abstracta y unificada.[^1]\n" +"En concepto básico, es similar a la forma en que los rasgos de Rust " +"funcionan con el borrado de tipos,\n" +"pero tiene un poco más de potencia y flexibilidad." + +#: src\functional/lenses.md:15 +#, fuzzy +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 "" +"Por ejemplo, suponga que un banco contiene varios formatos JSON para " +"clientes\n" +"datos.\n" +"Esto se debe a que provienen de diferentes bases de datos o sistemas " +"heredados.\n" +"Una base de datos contiene los datos necesarios para realizar verificaciones " +"de crédito:" + +#: 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 +#, fuzzy +msgid "Another one contains the account information:" +msgstr "Otro contiene la información de la cuenta:" + +#: 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 +#, fuzzy +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 "" +"Tenga en cuenta que ambos tipos tienen un número de identificación de " +"cliente que corresponde a una persona.\n" +"¿Cómo manejaría una sola función ambos registros de diferentes tipos?" + +#: src\functional/lenses.md:50 +#, fuzzy +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 "" +"En Rust, una `estructura` podría representar cada uno de estos tipos, y un " +"rasgo tendría\n" +"una función `get_customer_id` que implementarían:" + +#: 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 +#, fuzzy +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 "" +"Sin embargo, las lentes permiten que el código que respalda la " +"identificación del cliente se mueva de la\n" +"_type_ a la _función de acceso_.\n" +"En lugar de implementar un rasgo en cada tipo, todas las estructuras " +"coincidentes pueden\n" +"simplemente se puede acceder de la misma manera." + +#: src\functional/lenses.md:109 +#, fuzzy +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 "" +"Si bien el lenguaje Rust en sí mismo no admite esto (el borrado de tipo es " +"el\n" +"solución preferida para este problema), [lens-rs " +"crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) permite " +"código\n" +"que se siente así para ser escrito con macros:" + +#: 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 +#, fuzzy +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 "" +"La versión de `unique_ids_lens` que se muestra aquí permite que cualquier " +"tipo esté en el iterador,\n" +"siempre que tenga un atributo llamado `customer_id` al que se pueda acceder " +"mediante\n" +"la función.\n" +"Así es como la mayoría de los lenguajes de programación funcionales operan " +"en lentes." + +#: src\functional/lenses.md:154 +#, fuzzy +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 "" +"En lugar de macros, lo logran con una técnica conocida como \"curring\".\n" +"Es decir, \"construyen parcialmente\" la función, dejando el tipo de la\n" +"parámetro final (el valor que se está operando) sin completar hasta que la " +"función es\n" +"llamado.\n" +"Por lo tanto, se puede llamar con diferentes tipos dinámicamente incluso " +"desde un lugar en\n" +"el código.\n" +"Eso es lo que simula `optics!` y `view_ref` en el ejemplo anterior." + +#: src\functional/lenses.md:162 +#, fuzzy +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 "" +"El enfoque funcional no tiene por qué limitarse a los miembros de acceso.\n" +"Se pueden crear lentes más potentes que _configuran_ y _obtienen_ datos en " +"un\n" +"estructura.\n" +"Pero el concepto realmente se vuelve interesante cuando se usa como un " +"bloque de construcción para\n" +"composición.\n" +"Ahí es donde aparece más claro el concepto en Rust." + +#: src\functional/lenses.md:169 +#, fuzzy +msgid "## Prisms: A Higher-Order form of \"Optics\"" +msgstr "## Prismas: una forma de \"óptica\" de orden superior" + +#: src\functional/lenses.md:171 +#, fuzzy +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 "" +"Una función simple como `unique_ids_lens` anterior opera en una sola lente.\n" +"Un _prisma_ es una función que opera en una _familia_ de lentes.\n" +"Es un nivel conceptual más alto, usando lentes como bloque de construcción, " +"y\n" +"continuando con la metáfora, forma parte de una familia de \"ópticas\".\n" +"Es el principal que es útil para comprender las API de Rust, por lo que será " +"el\n" +"enfócate aquí." + +#: src\functional/lenses.md:178 +#, fuzzy +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 "" +"De la misma manera que los rasgos permiten un diseño \"similar a una lente\" " +"con polimorfismo estático y\n" +"envío dinámico, los diseños de prisma aparecen en las API de Rust que " +"dividen los problemas\n" +"en múltiples tipos asociados para ser compuestos.\n" +"Un buen ejemplo de esto son los rasgos en la caja de análisis _Serde_." + +#: src\functional/lenses.md:183 +#, fuzzy +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 "" +"Tratar de entender la forma en que funciona _Serde_ solo leyendo la API es " +"un\n" +"desafío, especialmente la primera vez.\n" +"Considere el rasgo `Deserializer`, implementado por algún tipo en cualquier " +"biblioteca\n" +"que analiza un nuevo formato:" + +#: 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 +#, fuzzy +msgid "" +"For a trait that is just supposed to parse data from a format and return a\n" +"value, this looks odd." +msgstr "" +"Para un rasgo que se supone que analiza datos de un formato y devuelve un\n" +"valor, esto parece extraño." + +#: src\functional/lenses.md:207 +#, fuzzy +msgid "Why are all the return types type erased?" +msgstr "¿Por qué se borran todos los tipos de devolución?" + +#: src\functional/lenses.md:209 +#, fuzzy +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 "" +"Para entender eso, necesitamos tener en mente el concepto de lente y " +"observar\n" +"la definición del tipo `Visitor` que se pasa genéricamente:" + +#: 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 +#, fuzzy +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 "" +"El trabajo del tipo `Visitor` es construir valores en el modelo de datos " +"_Serde_,\n" +"que están representados por su tipo `Valor` asociado." + +#: src\functional/lenses.md:235 +#, fuzzy +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 "" +"Estos valores representan partes del valor de Rust que se está " +"deserializando.\n" +"Si esto falla, devuelve un tipo `Error` - un tipo de error determinado por " +"el\n" +"`Deserializer` cuando se llamaron sus métodos." + +#: src\functional/lenses.md:239 +#, fuzzy +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 "" +"Esto resalta que `Deserializer` es similar a `CustomerId` anterior,\n" +"permitiendo que cualquier analizador de formato que lo implemente cree " +"'Valores' basados en lo que\n" +"analizó.\n" +"El rasgo `Valor` está actuando como una lente en los lenguajes de " +"programación funcionales." + +#: src\functional/lenses.md:244 +#, fuzzy +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 "" +"Pero a diferencia del rasgo `CustomerId`, los tipos de retorno de los " +"métodos `Visitor` son\n" +"_genérico_, y el tipo de `Valor` concreto es _determinado por el propio " +"Visitante_." + +#: src\functional/lenses.md:247 +#, fuzzy +msgid "" +"Instead of acting as one lens, it effectively acts as a family of\n" +"lenses, one for each concrete type of `Visitor`." +msgstr "" +"En lugar de actuar como una sola lente, actúa efectivamente como una familia " +"de\n" +"lentes, uno para cada tipo concreto de 'Visitante'." + +#: src\functional/lenses.md:250 +#, fuzzy +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 "" +"La API `Deserializer` se basa en tener un conjunto genérico de \"lentes\" " +"que funcionan en\n" +"un conjunto de otros tipos genéricos para \"observación\".\n" +"Es un _prisma_." + +#: src\functional/lenses.md:254 +#, fuzzy +msgid "For example, consider the identity record from earlier but simplified:" +msgstr "" +"Por ejemplo, considere el registro de identidad anterior pero simplificado:" + +#: src\functional/lenses.md:256 +msgid "" +"```json\n" +"{ \"name\": \"Jane Doe\",\n" +" \"customer_id\": 1048576332,\n" +"}\n" +"```" +msgstr "" + +#: src\functional/lenses.md:262 +#, fuzzy +msgid "" +"How would the _Serde_ library deserialize this JSON into `struct " +"CreditRecord`?" +msgstr "" +"¿Cómo deserializaría la biblioteca _Serde_ este JSON en `struct " +"CreditRecord`?" + +#: src\functional/lenses.md:264 +#, fuzzy +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 "" +"1. El usuario llamaría a una función de biblioteca para deserializar los " +"datos. Esto sería\n" +" cree un `Deserializador` basado en el formato JSON.\n" +"1. Según los campos de la estructura, se crearía un 'Visitante' (más sobre\n" +" eso en un momento) que sabe cómo crear cada tipo en un data genérico\n" +" modelo que se necesitaba para representarlo: `u64` y `String`.\n" +"1. El deserializador haría llamadas al `Visitor` mientras analizaba los " +"elementos.\n" +"1. El `Visitante` indicaría si los artículos encontrados eran los esperados, " +"y si no,\n" +" genera un error para indicar que la deserialización ha fallado." + +#: src\functional/lenses.md:273 +#, fuzzy +msgid "For our very simple structure above, the expected pattern would be:" +msgstr "Para nuestra estructura muy simple anterior, el patrón esperado sería:" + +#: src\functional/lenses.md:275 +#, fuzzy +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 "" +"1. Visitar un mapa (equivalente de _Serde_ a `HashMap` o diccionario de " +"JSON).\n" +"1. Visite una clave de cadena llamada \"nombre\".\n" +"1. Visite un valor de cadena, que irá al campo `nombre`.\n" +"1. Visite una clave de cadena llamada \"customer_id\".\n" +"1. Visite un valor de cadena, que irá al campo `customer_id`.\n" +"1. Visita el final del mapa." + +#: src\functional/lenses.md:282 +#, fuzzy +msgid "But what determines which \"observation\" pattern is expected?" +msgstr "Pero, ¿qué determina qué patrón de \"observación\" se espera?" + +#: src\functional/lenses.md:284 +#, fuzzy +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 "" +"Un lenguaje de programación funcional sería capaz de usar curry para crear\n" +"reflejo de cada tipo basado en el tipo mismo.\n" +"Rust no admite eso, por lo que cada tipo debería tener su propio\n" +"código escrito en base a sus campos y sus propiedades." + +#: src\functional/lenses.md:289 +#, fuzzy +msgid "_Serde_ solves this usability challenge with a derive macro:" +msgstr "_Serde_ resuelve este desafío de usabilidad con una macro derivada:" + +#: 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 +#, fuzzy +msgid "" +"That macro simply generates an impl block causing the struct to implement a\n" +"trait called `Deserialize`." +msgstr "" +"Esa macro simplemente genera un bloque impl que hace que la estructura " +"implemente un\n" +"rasgo llamado `Deserializar`." + +#: src\functional/lenses.md:304 +#, fuzzy +msgid "It is defined this way:" +msgstr "Se define de esta manera:" + +#: 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 +#, fuzzy +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 "" +"Esta es la función que determina cómo crear la estructura en sí.\n" +"El código se genera en función de los campos de la estructura.\n" +"Cuando se llama a la biblioteca de análisis, en nuestro ejemplo, una " +"biblioteca de análisis JSON,\n" +"crea un 'Deserializer' y llama a 'Type::deserialize' con él como un\n" +"parámetro." + +#: src\functional/lenses.md:320 +#, fuzzy +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 "" +"El código `deserialize` creará un `Visitor` que tendrá sus llamadas\n" +"\"refractado\" por el `Deserializador`.\n" +"Si todo va bien, eventualmente ese 'Visitante' construirá un valor\n" +"correspondiente al tipo que se está analizando y devolverlo." + +#: src\functional/lenses.md:325 +#, fuzzy +msgid "" +"For a complete example, see the [_Serde_ " +"documentation](https://serde.rs/deserialize-struct.html)." +msgstr "" +"Para ver un ejemplo completo, consulte la " +"[documentación_Serde_](https://serde.rs/deserialize-struct.html)." + +#: src\functional/lenses.md:327 +#, fuzzy +msgid "To wrap up, this is the power of _Serde_:" +msgstr "Para terminar, este es el poder de _Serde_:" + +#: src\functional/lenses.md:329 +#, fuzzy +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 "" +"1. La estructura que se analiza está representada por un bloque `impl` para " +"`Deserialize`\n" +"1. El formato de datos de entrada (por ejemplo, JSON) está representado por " +"un `Deserializador` llamado\n" +" por `Deserializar`\n" +"1. El 'Deserializador' actúa como un prisma que \"refracta\" al 'Visitor' " +"similar a una lente\n" +" llamadas que realmente construyen el valor de los datos" + +#: src\functional/lenses.md:335 +#, fuzzy +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 "" +"El resultado es que los tipos que se van a deserializar solo implementan la " +"\"capa superior\" de\n" +"la API y los formatos de archivo solo necesitan implementar la \"capa " +"inferior\".\n" +"Luego, cada pieza puede \"simplemente funcionar\" con el resto del " +"ecosistema, ya que los genéricos\n" +"los tipos los unirán." + +#: src\functional/lenses.md:340 +#, fuzzy +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 "" +"Para enfatizar, la única razón por la que este modelo funciona en cualquier " +"formato y cualquier tipo es\n" +"porque el tipo de salida del rasgo `Deserializer` ** está especificado por " +"el\n" +"implementador de `Visitor` se pasa **, en lugar de estar vinculado a un " +"específico\n" +"tipo.\n" +"Esto no era cierto en el ejemplo de la cuenta anterior." + +#: src\functional/lenses.md:346 +#, fuzzy +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 "" +"El sistema de tipos de inspiración genérica de Rust puede acercarlo a estos " +"conceptos y\n" +"usa su poder, como se muestra en este diseño de API.\n" +"Pero también puede necesitar macros de procedimiento para crear puentes para " +"sus genéricos." + +#: src\functional/lenses.md:350 +#, fuzzy +msgid "## See Also" +msgstr "## Ver también" + +#: src\functional/lenses.md:352 +#, fuzzy +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 "" +"- [caja de lentes-rs] (https://crates.io/crates/lens-rs) para lentes " +"preconstruidos\n" +" implementación, con una interfaz más limpia que estos ejemplos\n" +"- [serde](https://serde.rs) en sí mismo, lo que hace que estos conceptos " +"sean intuitivos para\n" +" usuarios finales (es decir, definir las estructuras) sin necesidad de " +"entender el\n" +" detalles\n" +"- [luminance](https://github.com/phaazon/luminance-rs) es una caja para " +"dibujar\n" +" gráficos por computadora que utilizan el diseño de la API de la lente, " +"incluidas las macros procesales para\n" +" crear prismas completos para búferes de diferentes tipos de píxeles que " +"siguen siendo genéricos\n" +"- [Un artículo sobre lentes en Scala] " +"(https://web.archive.org/web/20221128185849/https://medium.com/zyseme-technology/function-references-lens-and-other-optics-in- " +"scala-e5f7e2fdafe)\n" +" eso es muy legible incluso sin experiencia en Scala.\n" +"- [Papel: Óptica Profunctor: Datos Modulares\n" +" " +"Accesores](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf)" + +#: src\functional/lenses.md:365 +#, fuzzy +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 "" +"[Escuela de Haskell: un pequeño tutorial para principiantes de lentes] " +"la-semana/un-pequeño-lentes-inicio-tutorial)" + +#: src\additional_resources/index.md:1 +#, fuzzy +msgid "# Additional resources" +msgstr "# Recursos adicionales" + +#: src\additional_resources/index.md:3 +#, fuzzy +msgid "A collection of complementary helpful content" +msgstr "Una colección de contenido útil complementario" + +#: src\additional_resources/index.md:5 +#, fuzzy +msgid "## Talks" +msgstr "## Negociaciones" + +#: src\additional_resources/index.md:7 +#, fuzzy +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 "" +"- [Patrones de diseño en Rust](https://www.youtube.com/watch?v=Pm_oO0N5B9k) " +"por\n" +" Nicholas Cameron en el PDRust (2016)\n" +"- [Escribir bibliotecas idiomáticas en " +"Rust](https://www.youtube.com/watch?v=0zOg8_B71gE)\n" +" por Pascal Hertleif en RustFest (2017)\n" +"- [Técnicas de programación de óxido] " +"(https://www.youtube.com/watch?v=vqavdUGKeb4) por\n" +" Nicholas Cameron en LinuxConfAu (2018)" + +#: src\additional_resources/index.md:14 +#, fuzzy +msgid "## Books (Online)" +msgstr "## Libros (en línea)" + +#: src\additional_resources/index.md:16 +#, fuzzy +msgid "- [The Rust API Guidelines](https://rust-lang.github.io/api-guidelines)" +msgstr "" +"- [Las pautas de la API de Rust] (https://rust-lang.github.io/api-guidelines)" + +#: src\additional_resources/design-principles.md:1 +#, fuzzy +msgid "# Design principles" +msgstr "# Criterios de diseño" + +#: src\additional_resources/design-principles.md:3 +#, fuzzy +msgid "## A brief overview over common design principles" +msgstr "## Una breve descripción de los principios de diseño comunes" + +#: src\additional_resources/design-principles.md:7 +#, fuzzy +msgid "## [SOLID](https://en.wikipedia.org/wiki/SOLID)" +msgstr "## [SÓLIDO](https://en.wikipedia.org/wiki/SÓLIDO)" + +#: src\additional_resources/design-principles.md:9 +#, fuzzy +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 "" +"- [Principio de responsabilidad única (SRP)] " +"(https://en.wikipedia.org/wiki/Single-responsibility_principle):\n" +" Una clase solo debe tener una única responsabilidad, es decir, solo " +"cambios a\n" +" una parte de la especificación del software debería poder afectar la\n" +" especificación de la clase.\n" +"- [Principio abierto/cerrado " +"(OCP)](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle):\n" +" \"Las entidades de software... deberían estar abiertas para la extensión, " +"pero cerradas para\n" +" modificación.\"\n" +"- [Principio de sustitución de Liskov (LSP)] " +"(https://en.wikipedia.org/wiki/Liskov_substitution_principle):\n" +" \"Los objetos en un programa deben ser reemplazables con instancias de sus " +"subtipos\n" +" sin alterar la corrección de ese programa\".\n" +"- [Principio de segregación de interfaz (ISP)] " +"(https://en.wikipedia.org/wiki/Interface_segregation_principle):\n" +" \"Muchas interfaces específicas del cliente son mejores que una de " +"propósito general\n" +" interfaz.\"\n" +"- [Principio de inversión de dependencia (DIP)] " +"(https://en.wikipedia.org/wiki/Dependency_inversion_principle):\n" +" Uno debe \"depender de abstracciones, [no] de concreciones\"." + +#: src\additional_resources/design-principles.md:25 +#, fuzzy +msgid "" +"## [DRY (Don’t Repeat " +"Yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" +msgstr "" +"## [SECO (No te " +"repitas)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)" + +#: src\additional_resources/design-principles.md:27 +#, fuzzy +msgid "" +"\"Every piece of knowledge must have a single, unambiguous, authoritative\n" +"representation within a system\"" +msgstr "" +"“Cada pieza de conocimiento debe tener un único, inequívoco, autorizado\n" +"representación dentro de un sistema\"" + +#: src\additional_resources/design-principles.md:30 +#, fuzzy +msgid "## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle)" +msgstr "## [principio KISS](https://en.wikipedia.org/wiki/KISS_principle)" + +#: 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 +#, fuzzy +msgid "## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" +msgstr "## [Ley de Deméter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter)" + +#: src\additional_resources/design-principles.md:38 +#, fuzzy +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 "" +"un objeto dado debe suponer lo menos posible acerca de la estructura o\n" +"propiedades de cualquier otra cosa (incluidos sus subcomponentes), de " +"acuerdo con\n" +"el principio de \"ocultamiento de información\"" + +#: src\additional_resources/design-principles.md:42 +#, fuzzy +msgid "" +"## [Design by contract " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" +msgstr "" +"## [Diseño por contrato " +"(DbC)](https://en.wikipedia.org/wiki/Design_by_contract)" + +#: src\additional_resources/design-principles.md:44 +#, fuzzy +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 "" +"los diseñadores de software deben definir una interfaz formal, precisa y " +"verificable\n" +"especificaciones para componentes de software, que amplían la definición " +"ordinaria de\n" +"tipos de datos abstractos con condiciones previas, condiciones posteriores e " +"invariantes" + +#: src\additional_resources/design-principles.md:48 +#, fuzzy +msgid "" +"## " +"[Encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" +msgstr "" +"## " +"[Encapsulación](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))" + +#: src\additional_resources/design-principles.md:50 +#, fuzzy +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 "" +"agrupación de datos con los métodos que operan en esos datos, o la " +"restricción\n" +"de acceso directo a algunos de los componentes de un objeto. La " +"encapsulación se utiliza para\n" +"ocultar los valores o el estado de un objeto de datos estructurados dentro " +"de una clase, evitando\n" +"el acceso directo de terceros no autorizados a ellos." + +#: src\additional_resources/design-principles.md:55 +#, fuzzy +msgid "" +"## " +"[Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" +msgstr "" +"## [Comando-Consulta-Separación " +"(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)" + +#: src\additional_resources/design-principles.md:57 +#, fuzzy +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 "" +"“Las funciones no deben producir efectos secundarios abstractos... solo " +"comandos\n" +"(procedimientos) podrán producir efectos secundarios”. -Bertrand Meyer:\n" +"Construcción de software orientada a objetos" + +#: src\additional_resources/design-principles.md:61 +#, fuzzy +msgid "" +"## [Principle of least astonishment " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" +msgstr "" +"## [Principio del menor asombro " +"(POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)" + +#: src\additional_resources/design-principles.md:63 +#, fuzzy +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 "" +"un componente de un sistema debe comportarse de una manera que la mayoría de " +"los usuarios esperarán\n" +"a comportarse. El comportamiento no debe asombrar o sorprender a los " +"usuarios." + +#: src\additional_resources/design-principles.md:66 +#, fuzzy +msgid "## Linguistic-Modular-Units" +msgstr "## Unidades modulares lingüísticas" + +#: src\additional_resources/design-principles.md:68 +#, fuzzy +msgid "" +"“Modules must correspond to syntactic units in the language used.” - " +"Bertrand\n" +"Meyer: Object-Oriented Software Construction" +msgstr "" +"“Los módulos deben corresponder a unidades sintácticas en el idioma " +"utilizado.” - Bertrand\n" +"Meyer: Construcción de Software Orientado a Objetos" + +#: src\additional_resources/design-principles.md:71 +#, fuzzy +msgid "## Self-Documentation" +msgstr "## Autodocumentación" + +#: src\additional_resources/design-principles.md:73 +#, fuzzy +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 "" +"“El diseñador de un módulo debe esforzarse por hacer que toda la información " +"sobre el\n" +"módulo parte del propio módulo.” - Bertrand Meyer: software orientado a " +"objetos\n" +"Construcción" + +#: src\additional_resources/design-principles.md:77 +#, fuzzy +msgid "## Uniform-Access" +msgstr "## Acceso uniforme" + +#: src\additional_resources/design-principles.md:79 +#, fuzzy +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 "" +"“Todos los servicios ofrecidos por un módulo deben estar disponibles a " +"través de un\n" +"notación, que no traiciona si se implementan a través del almacenamiento o\n" +"a través de la computación.” - Bertrand Meyer: Construcción de Software " +"Orientado a Objetos" + +#: src\additional_resources/design-principles.md:83 +#, fuzzy +msgid "## Single-Choice" +msgstr "## Opción única" + +#: src\additional_resources/design-principles.md:85 +#, fuzzy +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 "" +"“Siempre que un sistema de software deba soportar un conjunto de " +"alternativas, una y sólo\n" +"un módulo en el sistema debe conocer su lista exhaustiva”. -Bertrand Meyer:\n" +"Construcción de software orientada a objetos" + +#: src\additional_resources/design-principles.md:89 +#, fuzzy +msgid "## Persistence-Closure" +msgstr "## Persistencia-Cierre" + +#: src\additional_resources/design-principles.md:91 +#, fuzzy +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 "" +"“Siempre que un mecanismo de almacenamiento almacena un objeto, debe " +"almacenar con él el\n" +"dependientes de ese objeto. Cada vez que un mecanismo de recuperación " +"recupera un\n" +"objeto previamente almacenado, también debe recuperar cualquier dependiente " +"de ese objeto\n" +"que aún no ha sido recuperado.” - Bertrand Meyer: software orientado a " +"objetos\n" +"Construcción" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + +msgid "" +msgstr "" + From 16a4e95d9982905483337a2939b3f383c3eb8bc6 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 9 Apr 2023 04:06:16 +0200 Subject: [PATCH 170/217] Fix symbolic link (#363) --- book.toml | 1 - theme/book.js | 0 2 files changed, 1 deletion(-) mode change 100644 => 120000 theme/book.js diff --git a/book.toml b/book.toml index 9154a482..f2bf36d9 100644 --- a/book.toml +++ b/book.toml @@ -24,7 +24,6 @@ git-repository-url = "https://github.com/rust-unofficial/patterns" git-repository-icon = "fa-github" edit-url-template = "https://github.com/rust-unofficial/patterns/edit/main/{path}" additional-css = ["./language-picker.css"] -additional-js = ["./third_party/mdbook/book.js"] [output.html.fold] enable = true diff --git a/theme/book.js b/theme/book.js deleted file mode 100644 index 43fb708d..00000000 --- a/theme/book.js +++ /dev/null @@ -1 +0,0 @@ -../third_party/mdbook/book.js \ No newline at end of file diff --git a/theme/book.js b/theme/book.js new file mode 120000 index 00000000..43fb708d --- /dev/null +++ b/theme/book.js @@ -0,0 +1 @@ +../third_party/mdbook/book.js \ No newline at end of file From bb8983f6fe1ceccb594374fb3eb7806c9cbcdf16 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sun, 23 Apr 2023 13:40:53 -0400 Subject: [PATCH 171/217] move ref_slice example and add historical note (#365) --- src/patterns/structural/small-crates.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/patterns/structural/small-crates.md b/src/patterns/structural/small-crates.md index 250db6b6..c652fc20 100644 --- a/src/patterns/structural/small-crates.md +++ b/src/patterns/structural/small-crates.md @@ -33,15 +33,15 @@ We should take advantage of this tooling, and use smaller, more fine-grained dep ## Examples -The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions -for converting `&T` to `&[T]`. - The [`url`](https://crates.io/crates/url) crate provides tools for working with URLs. The [`num_cpus`](https://crates.io/crates/num_cpus) crate provides a function to query the number of CPUs on a machine. +The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions +for converting `&T` to `&[T]`. (Historical example) + ## See also - [crates.io: The Rust community crate host](https://crates.io/) From 3a9e5de41c920d10889d519fb5e7d1ebfc15494e Mon Sep 17 00:00:00 2001 From: Patrik Pyrzanowski Date: Wed, 26 Apr 2023 09:26:13 +0200 Subject: [PATCH 172/217] Remove unknown `Context` identifier (#366) --- src/patterns/behavioural/strategy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/patterns/behavioural/strategy.md b/src/patterns/behavioural/strategy.md index e6e435c7..60892f2e 100644 --- a/src/patterns/behavioural/strategy.md +++ b/src/patterns/behavioural/strategy.md @@ -27,8 +27,7 @@ format, or just modify one of the existing formats. ## Example -In this example our invariants (or abstractions) are `Context`, `Formatter`, -and `Report`, while `Text` and `Json` are our strategy structs. These strategies +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. ```rust @@ -98,8 +97,9 @@ fn main() { The main advantage is separation of concerns. For example, in this case `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 context and a specific -trait and method to implement, i.e,`Formatter` and `run`. +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(...)`. ## Disadvantages From 70c6ca4c869595fec4b98d081626201faa747974 Mon Sep 17 00:00:00 2001 From: Owen Leung Date: Thu, 25 May 2023 21:45:39 +0800 Subject: [PATCH 173/217] docs(patterns): Add concrete examples for newtype and struct decomposition design patterns (#368) --- src/patterns/behavioural/newtype.md | 45 ++++----- src/patterns/structural/compose-structs.md | 112 ++++++++++++--------- 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/patterns/behavioural/newtype.md b/src/patterns/behavioural/newtype.md index 9e9f0195..d7b5a82e 100644 --- a/src/patterns/behavioural/newtype.md +++ b/src/patterns/behavioural/newtype.md @@ -17,42 +17,31 @@ This creates a new type, rather than an alias to a type (`type` items). ## Example -```rust,ignore -// Some type, not necessarily in the same module or even crate. -struct Foo { - //.. -} - -impl Foo { - // These functions are not present on Bar. - //.. -} - -// The newtype. -pub struct Bar(Foo); +```rust +use std::fmt::Display; -impl Bar { - // Constructor. - pub fn new( - //.. - ) -> Self { - - //.. +// Create Newtype Password to override the Display trait for String +struct Password(String); +impl Display for Password { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "****************") } - - //.. } fn main() { - let b = Bar::new(...); - - // Foo and Bar are type incompatible, the following do not type check. - // let f: Foo = b; - // let b: Bar = Foo { ... }; + let unsecured_password: String = "ThisIsMyPassword".to_string(); + let secured_password: Password = Password(unsecured_password.clone()); + println!("unsecured_password: {unsecured_password}"); + println!("secured_password: {secured_password}"); } ``` +```shell +unsecured_password: ThisIsMyPassword +secured_password: **************** +``` + ## Motivation The primary motivation for newtypes is abstraction. It allows you to share @@ -108,4 +97,4 @@ with `Bar`. - [Type aliases](https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases) - [derive_more](https://crates.io/crates/derive_more), a crate for deriving many builtin traits on newtypes. -- [The Newtype Pattern In Rust](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html) +- [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) diff --git a/src/patterns/structural/compose-structs.md b/src/patterns/structural/compose-structs.md index 013f6cb7..62fd30ed 100644 --- a/src/patterns/structural/compose-structs.md +++ b/src/patterns/structural/compose-structs.md @@ -1,6 +1,4 @@ -# Compose structs together for better borrowing - -TODO - this is not a very snappy name +# Struct decomposition for independent borrowing ## Description @@ -20,71 +18,93 @@ Here is a contrived example of where the borrow checker foils us in our plan to use a struct: ```rust -struct A { - f1: u32, - f2: u32, - f3: u32, +struct Database { + connection_string: String, + timeout: u32, + pool_size: u32, } -fn foo(a: &mut A) -> &u32 { &a.f2 } -fn bar(a: &mut A) -> u32 { a.f1 + a.f3 } +fn print_database(database: &Database) { + println!("Connection string: {}", database.connection_string); + println!("Timeout: {}", database.timeout); + println!("Pool size: {}", database.pool_size); +} -fn baz(a: &mut A) { - // The later usage of x causes a to be borrowed for the rest of the function. - let x = foo(a); - // Borrow checker error: - // let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once - // at a time - println!("{}", x); +fn main() { + let mut db = Database { + connection_string: "initial string".to_string(), + timeout: 30, + pool_size: 100, + }; + + let connection_string = &mut db.connection_string; + print_database(&db); // Immutable borrow of `db` happens here + // *connection_string = "new string".to_string(); // Mutable borrow is used + // here } ``` -We can apply this design pattern and refactor `A` into two smaller structs, thus -solving the borrow checking issue: +We can apply this design pattern and refactor `Database` into three smaller +structs, thus solving the borrow checking issue: ```rust -// A is now composed of two structs - B and C. -struct A { - b: B, - c: C, -} -struct B { - f2: u32, -} -struct C { - f1: u32, - f3: u32, +// Database is now composed of three structs - ConnectionString, Timeout and PoolSize. +// Let's decompose it into smaller structs +#[derive(Debug, Clone)] +struct ConnectionString(String); + +#[derive(Debug, Clone, Copy)] +struct Timeout(u32); + +#[derive(Debug, Clone, Copy)] +struct PoolSize(u32); + +// We then compose these smaller structs back into `Database` +struct Database { + connection_string: ConnectionString, + timeout: Timeout, + pool_size: PoolSize, } -// These functions take a B or C, rather than A. -fn foo(b: &mut B) -> &u32 { &b.f2 } -fn bar(c: &mut C) -> u32 { c.f1 + c.f3 } +// print_database can then take ConnectionString, Timeout and Poolsize struct instead +fn print_database(connection_str: ConnectionString, + timeout: Timeout, + pool_size: PoolSize) { + println!("Connection string: {:?}", connection_str); + println!("Timeout: {:?}", timeout); + println!("Pool size: {:?}", pool_size); +} -fn baz(a: &mut A) { - let x = foo(&mut a.b); - // Now it's OK! - let y = bar(&mut a.c); - println!("{}", x); +fn main() { + // Initialize the Database with the three structs + let mut db = Database { + connection_string: ConnectionString("localhost".to_string()), + timeout: Timeout(30), + pool_size: PoolSize(100), + }; + + let connection_string = &mut db.connection_string; + print_database(connection_string.clone(), db.timeout, db.pool_size); + *connection_string = ConnectionString("new string".to_string()); } ``` ## Motivation -TODO Why and where you should use the pattern +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. ## Advantages -Lets you work around limitations in the borrow checker. - -Often produces a better design. +Decomposition of structs lets you work around limitations in the borrow checker. +And it often produces a better design. ## Disadvantages -Leads to more verbose code. - -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. +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. ## Discussion From c455f960ca91d843eb61c07f069f826f30d56351 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 22:19:06 +0200 Subject: [PATCH 174/217] Bump actions/upload-pages-artifact from 1 to 2 (#369) Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 1 to 2. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/v1...v2) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ff333c3d..2b04282a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -58,7 +58,7 @@ jobs: uses: actions/configure-pages@v3 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v2 with: path: ./book From 12f6f988d4a6d81bf20e3f0f74c0e6c704351b36 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Fri, 18 Aug 2023 20:08:03 +0200 Subject: [PATCH 175/217] chore: reformat repository with dprint (#370) * chore: reformat repository with dprint * ci: change action name to reflect that it's not only markdown * fix: broken link --- .github/workflows/lint.yml | 2 +- .github/workflows/url-check-config.json | 10 +- .gitignore | 1 + CONTRIBUTING.md | 54 ++--- README.md | 21 +- dprint.json | 38 +++- src/additional_resources/design-principles.md | 33 ++- src/anti_patterns/borrow_clone.md | 26 ++- src/anti_patterns/deny-warnings.md | 5 +- src/anti_patterns/deref.md | 8 +- src/anti_patterns/index.md | 6 +- src/functional/generics-type-classes.md | 50 ++--- src/functional/index.md | 13 +- src/functional/lenses.md | 172 +++++++-------- src/functional/paradigms.md | 33 ++- src/idioms/coercion-arguments.md | 30 +-- src/idioms/concat-format.md | 3 +- src/idioms/ctor.md | 14 +- src/idioms/default.md | 10 +- src/idioms/deref.md | 12 +- src/idioms/dtor-finally.md | 3 +- src/idioms/ffi/accepting-strings.md | 32 ++- src/idioms/ffi/errors.md | 10 +- src/idioms/ffi/intro.md | 6 +- src/idioms/ffi/passing-strings.md | 10 +- src/idioms/index.md | 10 +- src/idioms/mem-replace.md | 37 ++-- src/idioms/on-stack-dyn-dispatch.md | 13 +- src/idioms/option-iter.md | 18 +- src/idioms/priv-extend.md | 82 ++++--- src/idioms/return-consumed-arg-on-error.md | 16 +- src/idioms/rustdoc-init.md | 7 +- src/idioms/temporary-mutability.md | 8 +- src/intro.md | 49 ++--- src/patterns/behavioural/RAII.md | 12 +- src/patterns/behavioural/command.md | 26 +-- src/patterns/behavioural/interpreter.md | 37 ++-- src/patterns/behavioural/intro.md | 4 +- src/patterns/behavioural/newtype.md | 21 +- src/patterns/behavioural/strategy.md | 72 ++++--- src/patterns/behavioural/visitor.md | 14 +- src/patterns/creational/builder.md | 13 +- src/patterns/creational/fold.md | 12 +- src/patterns/creational/intro.md | 9 +- src/patterns/ffi/export.md | 202 +++++++++--------- src/patterns/ffi/intro.md | 10 +- src/patterns/ffi/wrappers.md | 105 ++++----- src/patterns/index.md | 14 +- src/patterns/structural/intro.md | 4 +- src/patterns/structural/small-crates.md | 28 +-- src/patterns/structural/unsafe-mods.md | 13 +- src/refactoring/index.md | 15 +- src/translations.md | 6 +- template.md | 4 +- 54 files changed, 753 insertions(+), 710 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 236691e5..bf2ee6e5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Lint Markdown +name: Lint with dprint on: push: diff --git a/.github/workflows/url-check-config.json b/.github/workflows/url-check-config.json index dd50607f..3f96d792 100644 --- a/.github/workflows/url-check-config.json +++ b/.github/workflows/url-check-config.json @@ -1,7 +1,7 @@ { - "ignorePatterns": [ - { - "pattern": "^(http|https)://crates.io/" - } - ] + "ignorePatterns": [ + { + "pattern": "^(http|https)://crates.io/" + } + ] } diff --git a/.gitignore b/.gitignore index 29b71da3..4a27d130 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # Generated output of mdbook /book .DS_Store +.vscode/settings.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85c61b47..99ad8b39 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,15 +2,14 @@ ## Introduction -This book is a catalogue of Rust programming techniques, (anti-)patterns, -idioms and other explanations. It is a compilation of collective (sometimes -implicit) knowledge as well as experiences that have emerged through -collaborative work. +This book is a catalogue of Rust programming techniques, (anti-)patterns, idioms +and other explanations. It is a compilation of collective (sometimes implicit) +knowledge as well as experiences that have emerged through collaborative work. -The patterns described here are **not rules**, but should be taken as -guidelines for writing idiomatic code in Rust. We are collecting Rust patterns -in this book so people can learn the tradeoffs between Rust idioms and use them -properly in their own code. +The patterns described here are **not rules**, but should be taken as guidelines +for writing idiomatic code in Rust. We are collecting Rust patterns in this book +so people can learn the tradeoffs between Rust idioms and use them properly in +their own code. If you want to be part of this effort here are some ways you can participate: @@ -18,7 +17,8 @@ If you want to be part of this effort here are some ways you can participate: If you have a question or an idea regarding certain content, but you want to have feedback of fellow community members, and you think it may not be -appropriate to file an issue open a discussion in our [discussion board](https://github.com/rust-unofficial/patterns/discussions). +appropriate to file an issue open a discussion in our +[discussion board](https://github.com/rust-unofficial/patterns/discussions). ## Writing a new article @@ -30,11 +30,13 @@ there is an existing discussion or if someone is already working on that topic: - [Pull Requests](https://github.com/rust-unofficial/patterns/pulls) If you don't find an issue regarding your topic, and you are sure it is not more -feasible to open a thread in the [discussion board](https://github.com/rust-unofficial/patterns/discussions) -please open a new issue, so we can discuss the ideas and future content -of the article together and maybe give some feedback/input on it. +feasible to open a thread in the +[discussion board](https://github.com/rust-unofficial/patterns/discussions) +please open a new issue, so we can discuss the ideas and future content of the +article together and maybe give some feedback/input on it. -When writing a new article it's recommended to copy the [pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) +When writing a new article it's recommended to copy the +[pattern template](https://github.com/rust-unofficial/patterns/blob/master/template.md) into the appropriate directory and start editing it. You may not want to fill out every section and remove it, or you might want to add extra sections. @@ -43,12 +45,13 @@ Consider writing your article in a way that has a low barrier of entry so also the thought process behind it. So we can encourage people to use these patterns early on. -We encourage you to write idiomatic Rust code that builds in the [playground](https://play.rust-lang.org/). +We encourage you to write idiomatic Rust code that builds in the +[playground](https://play.rust-lang.org/). If you use links to blogposts or in general content that is not to be sure existing in a few years (e.g. pdfs) please take a snapshot with the -[Wayback Machine](https://web.archive.org/) and use the link to that snapshot -in your article. +[Wayback Machine](https://web.archive.org/) and use the link to that snapshot in +your article. Don't forget to add your new article to the `SUMMARY.md` to let it be rendered to the book. @@ -60,8 +63,10 @@ give early feedback (see the following section). In order to have a consistent style across the book, we suggest to: -- Follow the official Rust book's [style guide](https://github.com/rust-lang/book/blob/master/style-guide.md). -- Follow [RFC 1574](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text). +- Follow the official Rust book's + [style guide](https://github.com/rust-lang/book/blob/master/style-guide.md). +- Follow + [RFC 1574](https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text). Tl;dr: - Prefer full types name. For example `Option` instead of `Option`. - Prefer line comments (`//`) over block comments (`/* */`) where applicable. @@ -73,10 +78,11 @@ the book builds and `mdbook test` to make sure that code examples are correct. ### Markdown lint -To make sure the files comply with our Markdown style we use [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). -To spare you some manual work to get through the CI test you can use the -following commands to automatically fix most of the emerging problems when -writing Markdown files. +To make sure the files comply with our Markdown style we use +[markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli). To spare +you some manual work to get through the CI test you can use the following +commands to automatically fix most of the emerging problems when writing +Markdown files. - Install: @@ -96,8 +102,8 @@ writing Markdown files. "Release early and often!" also applies to pull requests! -Once your article has some visible work, create a `[WIP]` draft pull request -and give it a description of what you did or want to do. Early reviews of the +Once your article has some visible work, create a `[WIP]` draft pull request and +give it a description of what you did or want to do. Early reviews of the community are not meant as an offense but to give feedback. A good principle: "Work together, share ideas, teach others." diff --git a/README.md b/README.md index 3d960a8f..cdad7915 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,24 @@ language that you can read [here](https://rust-unofficial.github.io/patterns/). ## Contributing You are missing content in this repository that can be helpful for others, and -you are eager to explain it? Awesome! We are always happy about new contributions -(e.g. elaboration or corrections on certain topics) to this project. +you are eager to explain it? Awesome! We are always happy about new +contributions (e.g. elaboration or corrections on certain topics) to this +project. -You can check the [Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) -for all the patterns, anti-patterns, and idioms that could be added. +You can check the +[Umbrella issue](https://github.com/rust-unofficial/patterns/issues/116) for all +the patterns, anti-patterns, and idioms that could be added. -We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more information -on how contributing to this repository works. +We suggest reading our [Contribution guide](./CONTRIBUTING.md) to get more +information on how contributing to this repository works. ## Building with mdbook This book is built with [mdbook](https://rust-lang.github.io/mdBook/). You can install it by running `cargo install mdbook`. -If you want to build it locally you can run one of these two commands in the root -directory of the repository: +If you want to build it locally you can run one of these two commands in the +root directory of the repository: - `mdbook build` @@ -35,4 +37,5 @@ directory of the repository: ## License -The content of this repository is licensed under **MPL-2.0**; see [LICENSE](./LICENSE). +The content of this repository is licensed under **MPL-2.0**; see +[LICENSE](./LICENSE). diff --git a/dprint.json b/dprint.json index 66ee5b52..c4b0b9ff 100644 --- a/dprint.json +++ b/dprint.json @@ -1,11 +1,29 @@ { - "lineWidth": 80, - "markdown": {}, - "includes": [ - "**/*.{md}" - ], - "excludes": [], - "plugins": [ - "https://plugins.dprint.dev/markdown-0.15.2.wasm" - ] -} \ No newline at end of file + "lineWidth": 80, + "markdown": { + "lineWidth": 80, + "emphasisKind": "asterisks", + "strongKind": "asterisks", + "textWrap": "always" + }, + "toml": { + "lineWidth": 80 + }, + "json": { + "lineWidth": 80, + "indentWidth": 4 + }, + "includes": [ + "**/*.{md}", + "**/*.{toml}", + "**/*.{json}" + ], + "excludes": [ + "target/**/*" + ], + "plugins": [ + "https://plugins.dprint.dev/markdown-0.15.2.wasm", + "https://plugins.dprint.dev/toml-0.5.4.wasm", + "https://plugins.dprint.dev/json-0.17.4.wasm" + ] +} diff --git a/src/additional_resources/design-principles.md b/src/additional_resources/design-principles.md index d20ff914..daaea3b1 100644 --- a/src/additional_resources/design-principles.md +++ b/src/additional_resources/design-principles.md @@ -7,8 +7,8 @@ ## [SOLID](https://en.wikipedia.org/wiki/SOLID) - [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 + 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. - [Open/Closed Principle (OCP)](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle): "Software entities ... should be open for extension, but closed for @@ -30,8 +30,8 @@ representation within a system" ## [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) 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 +therefore, simplicity should be a key goal in design, and unnecessary complexity +should be avoided ## [Law of Demeter (LoD)](https://en.wikipedia.org/wiki/Law_of_Demeter) @@ -54,14 +54,14 @@ unauthorized parties' direct access to them. ## [Command-Query-Separation(CQS)](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) -“Functions should not produce abstract side effects...only commands -(procedures) will be permitted to produce side effects.” - Bertrand Meyer: -Object-Oriented Software Construction +“Functions should not produce abstract side effects...only commands (procedures) +will be permitted to produce side effects.” - Bertrand Meyer: Object-Oriented +Software Construction ## [Principle of least astonishment (POLA)](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) -a component of a system should behave in a way that most users will expect it -to behave. The behavior should not astonish or surprise users +a component of a system should behave in a way that most users will expect it to +behave. The behavior should not astonish or surprise users ## Linguistic-Modular-Units @@ -70,8 +70,8 @@ Meyer: Object-Oriented Software Construction ## Self-Documentation -“The designer of a module should strive to make all information about the -module part of the module itself.” - Bertrand Meyer: Object-Oriented Software +“The designer of a module should strive to make all information about the module +part of the module itself.” - Bertrand Meyer: Object-Oriented Software Construction ## Uniform-Access @@ -82,14 +82,13 @@ through computation.” - Bertrand Meyer: Object-Oriented Software Construction ## Single-Choice -“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: +“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: Object-Oriented Software Construction ## Persistence-Closure “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 +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 diff --git a/src/anti_patterns/borrow_clone.md b/src/anti_patterns/borrow_clone.md index f5806aa2..97482b4a 100644 --- a/src/anti_patterns/borrow_clone.md +++ b/src/anti_patterns/borrow_clone.md @@ -39,8 +39,8 @@ There are special cases -- `Rc` is designed to handle clones intelligently. It internally manages exactly one copy of the data, and cloning it will only clone the reference. -There is also `Arc` which provides shared ownership of a value of type T -that is allocated in the heap. Invoking `.clone()` on `Arc` produces a new `Arc` +There is also `Arc` which provides shared ownership of a value of type T that +is allocated in the heap. Invoking `.clone()` on `Arc` produces a new `Arc` instance, which points to the same allocation on the heap as the source `Arc`, while increasing a reference count. @@ -48,22 +48,26 @@ 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. -Even though `.clone()` is an indication of a bad pattern, sometimes -**it is fine to write inefficient code**, in cases such as when: +Even though `.clone()` is an indication of a bad pattern, sometimes **it is fine +to write inefficient code**, in cases such as when: - the developer is still new to ownership -- the code doesn't have great speed or memory constraints - (like hackathon projects or prototypes) +- the code doesn't have great speed or memory constraints (like hackathon + projects or prototypes) - satisfying the borrow checker is really complicated, and you prefer to optimize readability over performance -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. +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. -Also be sure to always run `cargo clippy` in your project, which will detect some -cases in which `.clone()` is not necessary, like [1](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone), +Also be sure to always run `cargo clippy` in your project, which will detect +some cases in which `.clone()` is not necessary, like +[1](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone), [2](https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy), -[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). +[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). ## See also diff --git a/src/anti_patterns/deny-warnings.md b/src/anti_patterns/deny-warnings.md index ec4bbda0..e5ca5f99 100644 --- a/src/anti_patterns/deny-warnings.md +++ b/src/anti_patterns/deny-warnings.md @@ -53,8 +53,9 @@ 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. -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): +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): ```rust,ignore #![deny(bad_style, diff --git a/src/anti_patterns/deref.md b/src/anti_patterns/deref.md index b6f8f789..5e04f88f 100644 --- a/src/anti_patterns/deref.md +++ b/src/anti_patterns/deref.md @@ -107,7 +107,8 @@ 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. +and this [RFC issue](https://github.com/rust-lang/rfcs/issues/349) for more +details. 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 @@ -123,6 +124,7 @@ conversion between arbitrary types. ## See also - [Collections are smart pointers idiom](../idioms/deref.md). -- Delegation crates for less boilerplate like [delegate](https://crates.io/crates/delegate) - or [ambassador](https://crates.io/crates/ambassador) +- Delegation crates for less boilerplate like + [delegate](https://crates.io/crates/delegate) or + [ambassador](https://crates.io/crates/ambassador) - [Documentation for `Deref` trait](https://doc.rust-lang.org/std/ops/trait.Deref.html). diff --git a/src/anti_patterns/index.md b/src/anti_patterns/index.md index 84107e04..896a1239 100644 --- a/src/anti_patterns/index.md +++ b/src/anti_patterns/index.md @@ -1,8 +1,8 @@ # Anti-patterns -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 +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 +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. diff --git a/src/functional/generics-type-classes.md b/src/functional/generics-type-classes.md index 5048ca77..44453838 100644 --- a/src/functional/generics-type-classes.md +++ b/src/functional/generics-type-classes.md @@ -4,9 +4,9 @@ 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. +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. 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. @@ -16,8 +16,8 @@ different types filled in. 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 +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. This is called **monomorphization**, where different types are created from @@ -37,9 +37,9 @@ makes them more usable while remaining safe. ## Example -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). +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). 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 @@ -63,10 +63,10 @@ struct FileDownloadRequest { } ``` -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. +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. 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 @@ -101,7 +101,7 @@ 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. -In Rust, this is actually possible! The solution is to _add a generic type_ in +In Rust, this is actually possible! The solution is to *add a generic type* in order to split the API. Here is what that looks like: @@ -187,8 +187,7 @@ fn main() { } ``` -With this approach, if the user were to make a mistake and use the wrong -type; +With this approach, if the user were to make a mistake and use the wrong type; ```rust,ignore fn main() { @@ -230,8 +229,8 @@ improve in the future. initialization, consider the [Builder Pattern](../patterns/creational/builder.md) instead. -- If the API between types does not change -- only the behavior does -- then - the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used +- If the API between types does not change -- only the behavior does -- then the + [Strategy Pattern](../patterns/behavioural/strategy.md) is better used instead. ## See also @@ -239,8 +238,8 @@ improve in the future. This pattern is used throughout the standard library: - `Vec` can be cast from a String, unlike every other type of `Vec`.[^1] -- They can also be cast into a binary heap, but only if they contain a type - that implements the `Ord` trait.[^2] +- They can also be cast into a binary heap, but only if they contain a type that + implements the `Ord` trait.[^2] - The `to_string` method was specialized for `Cow` only of type `str`.[^3] It is also used by several popular crates to allow API flexibility: @@ -248,8 +247,8 @@ It is also used by several popular crates to allow API flexibility: - 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] + it returns a `Pin` struct, whose generic determines the functions usable + in that mode, which are not on the `Pin` itself. [^4] - The `hyper` HTTP client library uses this to expose rich APIs for different pluggable requests. Clients with different connectors have different methods @@ -260,11 +259,14 @@ It is also used by several popular crates to allow API flexibility: internal state or invariant -- is implemented in Rust using the same basic concept, and a slightly different technique. [^6] -[^1]: See: [impl From\ for Vec\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811) +[^1]: See: +[impl From\ for Vec\](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811) -[^2]: See: [impl\ From\\> for BinaryHeap\](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354) +[^2]: 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) -[^3]: See: [impl\<'\_\> ToString for Cow\<'\_, str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) +[^3]: See: +[impl\<'\_\> ToString for Cow\<'\_, str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240) [^4]: 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) diff --git a/src/functional/index.md b/src/functional/index.md index 8be691f9..e9324b55 100644 --- a/src/functional/index.md +++ b/src/functional/index.md @@ -1,10 +1,11 @@ # Functional Usage of Rust Rust is an imperative language, but it follows many -[functional programming](https://en.wikipedia.org/wiki/Functional_programming) paradigms. +[functional programming](https://en.wikipedia.org/wiki/Functional_programming) +paradigms. -> 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. +> 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. diff --git a/src/functional/lenses.md b/src/functional/lenses.md index 3b160dff..d38354b6 100644 --- a/src/functional/lenses.md +++ b/src/functional/lenses.md @@ -1,21 +1,20 @@ # Lenses and Prisms This is a pure functional concept that is not frequently used in Rust. -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. +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. ## Lenses: Uniform Access Across Types -A lens is a concept from functional programming languages that allows -accessing parts of a data type in an abstract, unified way.[^1] -In basic concept, it is similar to the way Rust traits work with type erasure, -but it has a bit more power and flexibility. +A lens is a concept from functional programming languages that allows accessing +parts of a data type in an abstract, unified way.[^1] In basic concept, it is +similar to the way Rust traits work with type erasure, but it has a bit more +power and flexibility. -For example, suppose a bank contains several JSON formats for customer -data. -This is because they come from different databases or legacy systems. -One database contains the data needed to perform credit checks: +For example, suppose a bank contains several JSON formats for customer data. +This is because they come from different databases or legacy systems. One +database contains the data needed to perform credit checks: ```json { "name": "Jane Doe", @@ -102,13 +101,13 @@ fn unique_ids_iter(iterator: I) -> HashSet ``` Lenses, however, allow the code supporting customer ID to be moved from the -_type_ to the _accessor function_. -Rather than implementing a trait on each type, all matching structures can -simply be accessed the same way. +*type* to the *accessor function*. Rather than implementing a trait on each +type, all matching structures can simply be accessed the same way. While the Rust language itself does not support this (type erasure is the -preferred solution to this problem), the [lens-rs crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows code -that feels like this to be written with macros: +preferred solution to this problem), the +[lens-rs crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows +code that feels like this to be written with macros: ```rust,ignore use std::collections::HashSet; @@ -146,44 +145,39 @@ where } ``` -The version of `unique_ids_lens` shown here allows any type to be in the iterator, -so long as it has an attribute called `customer_id` which can be accessed by -the function. -This is how most functional programming languages operate on lenses. +The version of `unique_ids_lens` shown here allows any type to be in the +iterator, so long as it has an attribute called `customer_id` which can be +accessed by the function. This is how most functional programming languages +operate on lenses. -Rather than macros, they achieve this with a technique known as "currying". -That is, they "partially construct" the function, leaving the type of the -final parameter (the value being operated on) unfilled until the function is -called. +Rather than macros, they achieve this with a technique known as "currying". That +is, they "partially construct" the function, leaving the type of the final +parameter (the value being operated on) unfilled until the function is called. Thus it can be called with different types dynamically even from one place in -the code. -That is what the `optics!` and `view_ref` in the example above simulates. +the code. That is what the `optics!` and `view_ref` in the example above +simulates. -The functional approach need not be restricted to accessing members. -More powerful lenses can be created which both _set_ and _get_ data in a -structure. +The functional approach need not be restricted to accessing members. More +powerful lenses can be created which both *set* and *get* data in a structure. But the concept really becomes interesting when used as a building block for -composition. -That is where the concept appears more clearly in Rust. +composition. That is where the concept appears more clearly in Rust. ## Prisms: A Higher-Order form of "Optics" -A simple function such as `unique_ids_lens` above operates on a single lens. -A _prism_ is a function that operates on a _family_ of lenses. -It is one conceptual level higher, using lenses as a building block, and -continuing the metaphor, is part of a family of "optics". -It is the main one that is useful in understanding Rust APIs, so will be the -focus here. +A simple function such as `unique_ids_lens` above operates on a single lens. A +*prism* is a function that operates on a *family* of lenses. It is one +conceptual level higher, using lenses as a building block, and continuing the +metaphor, is part of a family of "optics". It is the main one that is useful in +understanding Rust APIs, so will be the focus here. The same way that traits allow "lens-like" design with static polymorphism and dynamic dispatch, prism-like designs appear in Rust APIs which split problems -into multiple associated types to be composed. -A good example of this is the traits in the parsing crate _Serde_. +into multiple associated types to be composed. A good example of this is the +traits in the parsing crate *Serde*. -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 some type in any library -which parses a new format: +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 some type in any library which parses a new format: ```rust,ignore pub trait Deserializer<'de>: Sized { @@ -206,8 +200,8 @@ value, this looks odd. Why are all the return types type erased? -To understand that, we need to keep the lens concept in mind and look at -the definition of the `Visitor` type that is passed in generically: +To understand that, we need to keep the lens concept in mind and look at the +definition of the `Visitor` type that is passed in generically: ```rust,ignore pub trait Visitor<'de>: Sized { @@ -229,50 +223,47 @@ pub trait Visitor<'de>: Sized { } ``` -The job of the `Visitor` type is to construct values in the _Serde_ data model, +The job of the `Visitor` type is to construct values in the *Serde* data model, which are represented by its associated `Value` type. -These values represent parts of the Rust value being deserialized. -If this fails, it returns an `Error` type - an error type determined by the +These values represent parts of the Rust value being deserialized. If this +fails, it returns an `Error` type - an error type determined by the `Deserializer` when its methods were called. This highlights that `Deserializer` is similar to `CustomerId` from earlier, allowing any format parser which implements it to create `Value`s based on what -it parsed. -The `Value` trait is acting like a lens in functional programming languages. +it parsed. The `Value` trait is acting like a lens in functional programming +languages. But unlike the `CustomerId` trait, the return types of `Visitor` methods are -_generic_, and the concrete `Value` type is _determined by the Visitor itself_. +*generic*, and the concrete `Value` type is *determined by the Visitor itself*. -Instead of acting as one lens, it effectively acts as a family of -lenses, one for each concrete type of `Visitor`. +Instead of acting as one lens, it effectively acts as a family of lenses, one +for each concrete type of `Visitor`. The `Deserializer` API is based on having a generic set of "lenses" work across -a set of other generic types for "observation". -It is a _prism_. +a set of other generic types for "observation". It is a *prism*. For example, consider the identity record from earlier but simplified: ```json -{ "name": "Jane Doe", - "customer_id": 1048576332, -} +{ "name": "Jane Doe", "customer_id": 1048576332 } ``` -How would the _Serde_ library deserialize this JSON into `struct CreditRecord`? +How would the *Serde* library deserialize this JSON into `struct CreditRecord`? 1. The user would call a library function to deserialize the data. This would create a `Deserializer` based on the JSON format. -1. 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: `u64` and `String`. +1. 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: `u64` and `String`. 1. The deserializer would make calls to the `Visitor` as it parsed items. 1. The `Visitor` would indicate if the items found were expected, and if not, raise an error to indicate deserialization has failed. For our very simple structure above, the expected pattern would be: -1. Visit a map (_Serde_'s equvialent to `HashMap` or JSON's dictionary). +1. Visit a map (*Serde*'s equvialent to `HashMap` or JSON's dictionary). 1. Visit a string key called "name". 1. Visit a string value, which will go into the `name` field. 1. Visit a string key called "customer_id". @@ -282,11 +273,11 @@ For our very simple structure above, the expected pattern would be: But what determines which "observation" pattern is expected? 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. +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. -_Serde_ solves this usability challenge with a derive macro: +*Serde* solves this usability challenge with a derive macro: ```rust,ignore use serde::Deserialize; @@ -311,49 +302,48 @@ pub trait Deserialize<'de>: Sized { } ``` -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. +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. 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. +"refracted" by the `Deserializer`. If everything goes well, eventually that +`Visitor` will construct a value corresponding to the type being parsed and +return it. -For a complete example, see the [_Serde_ documentation](https://serde.rs/deserialize-struct.html). +For a complete example, see the +[*Serde* documentation](https://serde.rs/deserialize-struct.html). -To wrap up, this is the power of _Serde_: +To wrap up, this is the power of *Serde*: -1. The structure being parsed is represented by an `impl` block for `Deserialize` +1. The structure being parsed is represented by an `impl` block for + `Deserialize` 1. The input data format (e.g. JSON) is represented by a `Deserializer` called by `Deserialize` 1. The `Deserializer` acts like a prism which "refracts" lens-like `Visitor` calls which actually build the data value 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. +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. To emphasize, the only reason this model works on any format and any type is -because the `Deserializer` trait's output type **is specified by the -implementor of `Visitor` it is passed**, rather than being tied to one specific -type. -This was not true in the account example earlier. +because the `Deserializer` trait's output type **is specified by the implementor +of `Visitor` it is passed**, rather than being tied to one specific type. This +was not true in the account example earlier. -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. +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. ## See Also - [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses implementation, with a cleaner interface than these examples -- [serde](https://serde.rs) itself, which makes these concepts intuitive for - end users (i.e. defining the structs) without needing to undestand the - details +- [serde](https://serde.rs) itself, which makes these concepts intuitive for end + users (i.e. defining the structs) without needing to undestand the details - [luminance](https://github.com/phaazon/luminance-rs) is a crate for drawing computer graphics that uses lens API design, including proceducal macros to create full prisms for buffers of different pixel types that remain generic diff --git a/src/functional/paradigms.md b/src/functional/paradigms.md index 099fd785..4f7c11b6 100644 --- a/src/functional/paradigms.md +++ b/src/functional/paradigms.md @@ -1,9 +1,9 @@ # Programming paradigms -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. +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. ## Imperative @@ -16,9 +16,8 @@ println!("{}", sum); ``` 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. +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. | `i` | `sum` | @@ -43,17 +42,17 @@ of steps. println!("{}", (1..11).fold(0, |a, b| a + b)); ``` -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. +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. -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`. +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`. | `a` | `b` | result | | :-: | :-: | :----: | diff --git a/src/idioms/coercion-arguments.md b/src/idioms/coercion-arguments.md index e37d63c4..9291d90b 100644 --- a/src/idioms/coercion-arguments.md +++ b/src/idioms/coercion-arguments.md @@ -3,12 +3,11 @@ ## Description 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. +when you are deciding which argument type to use for a function argument. In +this way, the function will accept more input types. -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**. +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`. Using borrowed types you can avoid layers of indirection for those instances @@ -59,10 +58,10 @@ fn main() { } ``` -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. +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. For instance, if we change our function declaration to: @@ -77,11 +76,11 @@ Ferris: false Curious: true ``` -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`. +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`. 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. @@ -128,7 +127,8 @@ curious has three consecutive vowels! 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 `&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. +is not implicit, whereas converting from `String` to `&str` is cheap and +implicit. ## See also diff --git a/src/idioms/concat-format.md b/src/idioms/concat-format.md index 372d86e5..8053a9cb 100644 --- a/src/idioms/concat-format.md +++ b/src/idioms/concat-format.md @@ -24,7 +24,8 @@ fn say_hello(name: &str) -> String { ## Advantages -Using `format!` is usually the most succinct and readable way to combine strings. +Using `format!` is usually the most succinct and readable way to combine +strings. ## Disadvantages diff --git a/src/idioms/ctor.md b/src/idioms/ctor.md index 13e0cc6a..78bab8d6 100644 --- a/src/idioms/ctor.md +++ b/src/idioms/ctor.md @@ -2,8 +2,9 @@ ## Description -Rust does not have constructors as a language construct. Instead, the -convention is to use an [associated function][associated function] `new` to create an object: +Rust does not have constructors as a language construct. Instead, the convention +is to use an [associated function][associated function] `new` to create an +object: ````rust /// Time in seconds. @@ -88,11 +89,10 @@ impl Second { } ```` -**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. +**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. **Hint:** The advantage of implementing or deriving `Default` is that your type can now be used where a `Default` implementation is required, most prominently, diff --git a/src/idioms/default.md b/src/idioms/default.md index 3954b8b9..f383df30 100644 --- a/src/idioms/default.md +++ b/src/idioms/default.md @@ -2,11 +2,11 @@ ## Description -Many types in Rust have a [constructor]. However, this is _specific_ to the -type; Rust cannot abstract over "everything that has a `new()` method". To -allow this, the [`Default`] trait was conceived, which can be used with -containers and other generic types (e.g. see [`Option::unwrap_or_default()`]). -Notably, some containers already implement it where applicable. +Many types in Rust have a [constructor]. However, this is *specific* to the +type; Rust cannot abstract over "everything that has a `new()` method". To allow +this, the [`Default`] trait was conceived, which can be used with containers and +other generic types (e.g. see [`Option::unwrap_or_default()`]). Notably, some +containers already implement it where applicable. Not only do one-element containers like `Cow`, `Box` or `Arc` implement `Default` for contained `Default` types, one can automatically diff --git a/src/idioms/deref.md b/src/idioms/deref.md index 0f6d9aeb..e2f284eb 100644 --- a/src/idioms/deref.md +++ b/src/idioms/deref.md @@ -2,9 +2,9 @@ ## Description -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. +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. ## Example @@ -36,9 +36,9 @@ Also `String` and `&str` have a similar relation. ## Motivation Ownership and borrowing are key aspects of the Rust language. Data structures -must account for these semantics properly to give a good user -experience. When implementing a data structure that owns its data, offering a -borrowed view of that data allows for more flexible APIs. +must account for these semantics properly to give a good user experience. When +implementing a data structure that owns its data, offering a borrowed view of +that data allows for more flexible APIs. ## Advantages diff --git a/src/idioms/dtor-finally.md b/src/idioms/dtor-finally.md index 45152905..f0f82b26 100644 --- a/src/idioms/dtor-finally.md +++ b/src/idioms/dtor-finally.md @@ -56,7 +56,8 @@ This pattern introduces some hard to notice, implicit code. Reading a function gives no clear indication of destructors to be run on exit. This can make debugging tricky. -Requiring an object and `Drop` impl just for finalisation is heavy on boilerplate. +Requiring an object and `Drop` impl just for finalisation is heavy on +boilerplate. ## Discussion diff --git a/src/idioms/ffi/accepting-strings.md b/src/idioms/ffi/accepting-strings.md index 8e0ca84c..f86873fc 100644 --- a/src/idioms/ffi/accepting-strings.md +++ b/src/idioms/ffi/accepting-strings.md @@ -16,12 +16,12 @@ The strings used in C have different behaviours to those used in Rust, namely: - C strings are null-terminated while Rust strings store their length - C strings can contain any arbitrary non-zero byte while Rust strings must be UTF-8 -- C strings are accessed and manipulated using `unsafe` pointer operations - 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 The Rust standard library comes with C equivalents of Rust's `String` and `&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. +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. The `&CStr` type also allows us to work with borrowed data, meaning passing strings between Rust and C is a zero-cost operation. @@ -70,8 +70,7 @@ pub mod unsafe_module { The example is is written to ensure that: 1. The `unsafe` block is as small as possible. -2. The pointer with an "untracked" lifetime becomes a "tracked" shared - reference +2. The pointer with an "untracked" lifetime becomes a "tracked" shared reference Consider an alternative, where the string is actually copied: @@ -121,22 +120,21 @@ This code in inferior to the original in two respects: 1. There is much more `unsafe` code, and more importantly, more invariants it must uphold. -2. Due to the extensive arithmetic required, there is a bug in this version - that cases Rust `undefined behaviour`. +2. Due to the extensive arithmetic required, there is a bug in this version that + cases Rust `undefined behaviour`. The bug here is a simple mistake in pointer arithmetic: the string was copied, all `msg_len` bytes of it. However, the `NUL` terminator at the end was not. -The Vector then had its size _set_ to the length of the _zero padded string_ -- -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`! +The Vector then had its size *set* to the length of the *zero padded string* -- +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`! -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 -put a weird character at the end of the string, sometimes it would just -completely crash. +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 put a weird +character at the end of the string, sometimes it would just completely crash. ## Disadvantages diff --git a/src/idioms/ffi/errors.md b/src/idioms/ffi/errors.md index f254aea0..5d5bed02 100644 --- a/src/idioms/ffi/errors.md +++ b/src/idioms/ffi/errors.md @@ -2,9 +2,9 @@ ## Description -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 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 +propogated through a full type. This best practice shows different kinds of error codes, and how to expose them in a usable way: @@ -135,5 +135,5 @@ while not compromising the Rust code's API at all. ## Disadvantages -It's a lot of typing, and some types may not be able to be converted easily -to C. +It's a lot of typing, and some types may not be able to be converted easily to +C. diff --git a/src/idioms/ffi/intro.md b/src/idioms/ffi/intro.md index 93b4862e..e8bc4cda 100644 --- a/src/idioms/ffi/intro.md +++ b/src/idioms/ffi/intro.md @@ -1,8 +1,8 @@ # FFI Idioms -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. +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. This section contains idioms that may be useful when doing FFI. diff --git a/src/idioms/ffi/passing-strings.md b/src/idioms/ffi/passing-strings.md index cd540614..3b4056dd 100644 --- a/src/idioms/ffi/passing-strings.md +++ b/src/idioms/ffi/passing-strings.md @@ -17,11 +17,11 @@ 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 are being sent to a foreign function call from a Rust function. -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. +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. ## Code Example diff --git a/src/idioms/index.md b/src/idioms/index.md index 22ebed6a..014e5da5 100644 --- a/src/idioms/index.md +++ b/src/idioms/index.md @@ -1,13 +1,11 @@ # Idioms [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. +styles, guidelines and patterns largely agreed upon by a community. Writing +idiomatic code allows other developers to understand better what is happening. -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. +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? Remember the [KISS principle](https://en.wikipedia.org/wiki/KISS_principle): diff --git a/src/idioms/mem-replace.md b/src/idioms/mem-replace.md index 1771f2ad..ab2d431e 100644 --- a/src/idioms/mem-replace.md +++ b/src/idioms/mem-replace.md @@ -58,27 +58,29 @@ fn swizzle(e: &mut MultiVariateEnum) { When working with enums, we may want to change an enum value in place, 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). +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). 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 -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. +*something* must be there.) We could of course `.clone()` name and put the 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. `mem::take` lets us swap out the value, replacing it with it's default value, and returning the previous value. For `String`, the default value is an 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. +`name` *as an owned value*. We can then wrap this in another enum. **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())`. -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. +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. ## Advantages @@ -86,13 +88,13 @@ Look ma, no allocation! Also you may feel like Indiana Jones while doing it. ## Disadvantages -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. +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. -Furthermore, the type you are taking needs to implement the [`Default` trait](./default.md). However, if the type you're working with doesn't -implement this, you can instead use `mem::replace`. +Furthermore, the type you are taking needs to implement the +[`Default` trait](./default.md). However, if the type you're working with +doesn't implement this, you can instead use `mem::replace`. ## Discussion @@ -107,5 +109,6 @@ like Indiana Jones, replacing the artifact with a bag of sand. ## See also -This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md) +This gets rid of the +[Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md) anti-pattern in a specific case. diff --git a/src/idioms/on-stack-dyn-dispatch.md b/src/idioms/on-stack-dyn-dispatch.md index 5ecb31af..14a592ba 100644 --- a/src/idioms/on-stack-dyn-dispatch.md +++ b/src/idioms/on-stack-dyn-dispatch.md @@ -2,8 +2,8 @@ ## Description -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 +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 lifetime as necessary, we can use deferred conditional initialization, as seen below: @@ -68,7 +68,7 @@ let readable: Box = if arg == "-" { ## Discussion Rust newcomers will usually learn that Rust requires all variables to be -initialized _before use_, so it's easy to overlook the fact that _unused_ +initialized *before use*, so it's easy to overlook the fact that *unused* variables may well be uninitialized. Rust works quite hard to ensure that this works out fine and only the initialized values are dropped at the end of their scope. @@ -77,14 +77,15 @@ The example meets all the constraints Rust places on us: - All variables are initialized before using (in this case borrowing) them - Each variable only holds values of a single type. In our example, `stdin` is - of type `Stdin`, `file` is of type `File` and `readable` is of type `&mut dyn Read` + of type `Stdin`, `file` is of type `File` and `readable` is of type + `&mut dyn Read` - Each borrowed value outlives all the references borrowed from it ## See also - [Finalisation in destructors](dtor-finally.md) and - [RAII guards](../patterns/behavioural/RAII.md) can benefit from tight control over - lifetimes. + [RAII guards](../patterns/behavioural/RAII.md) can benefit from tight control + over lifetimes. - For conditionally filled `Option<&T>`s of (mutable) references, one can initialize an `Option` directly and use its [`.as_ref()`] method to get an optional reference. diff --git a/src/idioms/option-iter.md b/src/idioms/option-iter.md index f8ac9f97..350fbb7b 100644 --- a/src/idioms/option-iter.md +++ b/src/idioms/option-iter.md @@ -2,9 +2,9 @@ ## Description -`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. +`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. ## Examples @@ -23,8 +23,9 @@ if let Some(turing_inner) = turing { } ``` -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): +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): ```rust let turing = Some("Turing"); @@ -39,8 +40,8 @@ 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. -Also, since `Option` implements `IntoIterator`, it's possible to iterate over -it using a `for` loop. This is equivalent to matching it with `if let Some(..)`, +Also, since `Option` implements `IntoIterator`, it's possible to iterate 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. ## See also @@ -50,7 +51,8 @@ and in most cases you should prefer the latter. `Some(foo).into_iter()`. - [`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), + 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`. - The [`ref_slice`](https://crates.io/crates/ref_slice) crate provides functions diff --git a/src/idioms/priv-extend.md b/src/idioms/priv-extend.md index 2a14fdb4..452b6614 100644 --- a/src/idioms/priv-extend.md +++ b/src/idioms/priv-extend.md @@ -8,9 +8,10 @@ compatibility. Rust offers two solutions to this problem: -- 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). +- 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). - You may add a private field to a struct to prevent it from being directly instantiated or matched against (see Alternative) @@ -56,22 +57,21 @@ fn print_matched_variants(s: a::S) { ## Alternative: `Private fields` for structs -`#[non_exhaustive]` only works across crate boundaries. -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. -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 -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. +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 +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. -The downside of this approach is that you might need to add an otherwise 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. +The downside of this approach is that you might need to add an otherwise +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. ```rust pub struct S { @@ -85,37 +85,33 @@ pub struct S { ## Discussion On `struct`s, `#[non_exhaustive]` allows adding additional fields in a 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. - -`#[non_exhaustive]` can be applied to enum variants as well. -A `#[non_exhaustive]` variant behaves in the same way as a `#[non_exhaustive]` struct. - -Use this deliberately and with caution: incrementing the major version when 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. +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. + +`#[non_exhaustive]` can be applied to enum variants as well. A +`#[non_exhaustive]` variant behaves in the same way as a `#[non_exhaustive]` +struct. + +Use this deliberately and with caution: incrementing the major version when +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. ### Disadvantages -`#[non_exhaustive]` can make your code much less ergonomic to use, 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. +`#[non_exhaustive]` can make your code much less ergonomic to use, 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. When `#[non_exhaustive]` is applied to `enum`s, it forces clients to handle 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. +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. ## See also diff --git a/src/idioms/return-consumed-arg-on-error.md b/src/idioms/return-consumed-arg-on-error.md index 6a0c471f..75369d2f 100644 --- a/src/idioms/return-consumed-arg-on-error.md +++ b/src/idioms/return-consumed-arg-on-error.md @@ -2,8 +2,8 @@ ## Description -If a fallible function consumes (moves) an argument, return that argument back inside -an error. +If a fallible function consumes (moves) an argument, return that argument back +inside an error. ## Example @@ -42,14 +42,12 @@ fn main() { ## Motivation -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. +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. -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. +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. ## Advantages diff --git a/src/idioms/rustdoc-init.md b/src/idioms/rustdoc-init.md index da0291a3..d3847d2b 100644 --- a/src/idioms/rustdoc-init.md +++ b/src/idioms/rustdoc-init.md @@ -80,9 +80,10 @@ This is much more concise and avoids repetitive code in examples. ## Disadvantages -As example is in a function, the code will not be tested. Though it will 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`. +As example is in a function, the code will not be tested. Though it will 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`. ## Discussion diff --git a/src/idioms/temporary-mutability.md b/src/idioms/temporary-mutability.md index e630e102..f9cc9d37 100644 --- a/src/idioms/temporary-mutability.md +++ b/src/idioms/temporary-mutability.md @@ -3,8 +3,8 @@ ## Description Often it is necessary to prepare and process some data, but after that data are -only inspected and never modified. The intention can be made explicit by redefining -the mutable variable as immutable. +only inspected and never modified. The intention can be made explicit by +redefining the mutable variable as immutable. It can be done either by processing data within a nested block or by redefining the variable. @@ -41,5 +41,5 @@ Compiler ensures that you don't accidentally mutate data after some point. ## Disadvantages -Nested block requires additional indentation of block body. -One more line to return data from block or redefine variable. +Nested block requires additional indentation of block body. One more line to +return data from block or redefine variable. diff --git a/src/intro.md b/src/intro.md index 71c8f88b..1f70e3db 100644 --- a/src/intro.md +++ b/src/intro.md @@ -7,34 +7,31 @@ If you are interested in contributing to this book, check out the ## Design patterns -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. - -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. +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. + +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. ## Design patterns in Rust 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: - -- [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. -- [Design patterns](./patterns/index.md): methods to solve common problems - when coding. +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: + +- [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. +- [Design patterns](./patterns/index.md): methods to solve common problems when + coding. - [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. + when coding. However, while design patterns give us benefits, anti-patterns + create more problems. diff --git a/src/patterns/behavioural/RAII.md b/src/patterns/behavioural/RAII.md index 4b3f4409..6a247884 100644 --- a/src/patterns/behavioural/RAII.md +++ b/src/patterns/behavioural/RAII.md @@ -3,10 +3,11 @@ ## Description [RAII][wikipedia] 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. +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. ## Example @@ -112,7 +113,8 @@ works just as well. [Finalisation in destructors idiom](../../idioms/dtor-finally.md) -RAII is a common pattern in C++: [cppreference.com](http://en.cppreference.com/w/cpp/language/raii), +RAII is a common pattern in C++: +[cppreference.com](http://en.cppreference.com/w/cpp/language/raii), [wikipedia][wikipedia]. [wikipedia]: https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization diff --git a/src/patterns/behavioural/command.md b/src/patterns/behavioural/command.md index 1e0ae263..969f5849 100644 --- a/src/patterns/behavioural/command.md +++ b/src/patterns/behavioural/command.md @@ -9,11 +9,11 @@ objects and pass them as parameters. Suppose we have a sequence of actions or transactions encapsulated as 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. +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. +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. ## Example @@ -94,8 +94,8 @@ fn main() { ## Approach: Using function pointers -We could follow another approach by creating each individual command as -a different function and store function pointers to invoke these functions later +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. @@ -149,8 +149,8 @@ fn main() { ## Approach: Using `Fn` trait objects -Finally, instead of defining a common command trait we could store -each command implementing the `Fn` trait separately in vectors. +Finally, instead of defining a common command trait we could store each command +implementing the `Fn` trait separately in vectors. ```rust type Migration<'a> = Box &'a str>; @@ -205,11 +205,11 @@ fn main() { If our commands are small and may be defined as functions or passed as a 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 seperated 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. +and variables defined as seperated 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. As performance, there is always a trade-off between performance and code simplicity and organisation. Static dispatch gives faster performance, while diff --git a/src/patterns/behavioural/interpreter.md b/src/patterns/behavioural/interpreter.md index 854331ba..b6803e37 100644 --- a/src/patterns/behavioural/interpreter.md +++ b/src/patterns/behavioural/interpreter.md @@ -9,23 +9,25 @@ simple language. Basically, for any kind of problems we define: -- A [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language), +- A + [domain specific language](https://en.wikipedia.org/wiki/Domain-specific_language), - A grammar for this language, - An interpreter that solves the problem instances. ## Motivation -Our goal is to translate simple mathematical expressions into postfix expressions -(or [Reverse Polish notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation)) +Our goal is to translate simple mathematical expressions into postfix +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 +`. ## Context Free Grammar for our problem -Our task is translating infix expressions into postfix ones. Let's define a context -free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and `-`, -where: +Our task is translating infix expressions into postfix ones. Let's define a +context free grammar for a set of infix expressions over `0`, ..., `9`, `+`, and +`-`, where: - Terminal symbols: `0`, `...`, `9`, `+`, `-` - Non-terminal symbols: `exp`, `term` @@ -39,9 +41,10 @@ exp -> term term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ``` -**NOTE:** This grammar should be further transformed depending on what we 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) +**NOTE:** This grammar should be further transformed depending on what we 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). ## Solution @@ -102,18 +105,18 @@ pub fn main() { ## Discussion -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. +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. 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. +efficient than packing `x,1,2` into a `Vec` and calling a function computing the +length. ```rust macro_rules! norm { diff --git a/src/patterns/behavioural/intro.md b/src/patterns/behavioural/intro.md index 8ca43a04..3151247b 100644 --- a/src/patterns/behavioural/intro.md +++ b/src/patterns/behavioural/intro.md @@ -2,5 +2,5 @@ From [Wikipedia](https://en.wikipedia.org/wiki/Behavioral_pattern): -> Design patterns that identify common communication patterns among objects. -> By doing so, these patterns increase flexibility in carrying out communication. +> Design patterns that identify common communication patterns among objects. By +> doing so, these patterns increase flexibility in carrying out communication. diff --git a/src/patterns/behavioural/newtype.md b/src/patterns/behavioural/newtype.md index d7b5a82e..8d19f8fd 100644 --- a/src/patterns/behavioural/newtype.md +++ b/src/patterns/behavioural/newtype.md @@ -1,14 +1,14 @@ # Newtype 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? +enforce some behaviour at compile time when using only type aliases would not be +enough? For example, if we want to create a custom `Display` implementation for `String` due to security considerations (e.g. passwords). -For such cases we could use the `Newtype` pattern to provide **type safety** -and **encapsulation**. +For such cases we could use the `Newtype` pattern to provide **type safety** and +**encapsulation**. ## Description @@ -66,7 +66,7 @@ field is private, which it is by default). ## Disadvantages The downside of newtypes (especially compared with type aliases), is that there -is no special language support. This means there can be _a lot_ of boilerplate. +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. @@ -76,7 +76,8 @@ the wrapper type. Newtypes are very common in Rust code. Abstraction or representing units are the most common uses, but they can be used for other reasons: -- restricting functionality (reduce the functions exposed or traits implemented), +- restricting functionality (reduce the functions exposed or traits + implemented), - making a type with copy semantics have move semantics, - abstraction by providing a more concrete type and thus hiding internal types, e.g., @@ -85,10 +86,10 @@ most common uses, but they can be used for other reasons: pub struct Foo(Bar); ``` -Here, `Bar` might be some public, generic type and `T1` and `T2` are some 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`. +Here, `Bar` might be some public, generic type and `T1` and `T2` are some +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`. ## See also diff --git a/src/patterns/behavioural/strategy.md b/src/patterns/behavioural/strategy.md index 60892f2e..92c0a7a3 100644 --- a/src/patterns/behavioural/strategy.md +++ b/src/patterns/behavioural/strategy.md @@ -2,33 +2,36 @@ ## Description -The [Strategy design pattern](https://en.wikipedia.org/wiki/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). +The [Strategy design pattern](https://en.wikipedia.org/wiki/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). -The basic idea behind the Strategy pattern is that, given an algorithm 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. +The basic idea behind the Strategy pattern is that, given an algorithm 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. In this way, a client using the algorithm may choose a specific 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". +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". ## Motivation -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. +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. ## Example -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. +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. ```rust use std::collections::HashMap; @@ -97,37 +100,38 @@ fn main() { The main advantage is separation of concerns. For example, in this case `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(...)`. +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(...)`. ## Disadvantages -For each strategy there must be implemented at least one module, so number 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. +For each strategy there must be implemented at least one module, so number 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. ## Discussion -In the previous example all strategies are implemented in a single file. -Ways of providing different strategies includes: +In the previous example all strategies are implemented in a single file. Ways of +providing different strategies includes: -- All in one file (as shown in this example, similar to being separated as modules) +- All in one file (as shown in this example, similar to being separated as + modules) - Separated as modules, E.g. `formatter::json` module, `formatter::text` module - Use compiler feature flags, E.g. `json` feature, `text` feature - Separated as crates, E.g. `json` crate, `text` crate Serde crate is a good example of the `Strategy` pattern in action. Serde 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. +[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. However, we don't need to use traits in order to design this pattern in Rust. -The following toy example demonstrates the idea of the Strategy pattern using Rust -`closures`: +The following toy example demonstrates the idea of the Strategy pattern using +Rust `closures`: ```rust struct Adder; diff --git a/src/patterns/behavioural/visitor.md b/src/patterns/behavioural/visitor.md index 55873147..c164d2a9 100644 --- a/src/patterns/behavioural/visitor.md +++ b/src/patterns/behavioural/visitor.md @@ -7,8 +7,8 @@ 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). -Furthermore, the visitor pattern allows separating the traversal of -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. ## Example @@ -72,9 +72,9 @@ to modify the AST data. ## Motivation The visitor pattern is useful anywhere that you want to apply an algorithm 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. +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. ## Discussion @@ -109,5 +109,5 @@ The visitor pattern is a common pattern in most OO languages. [Wikipedia article](https://en.wikipedia.org/wiki/Visitor_pattern) -The [fold](../creational/fold.md) pattern is similar to visitor but produces -a new version of the visited data structure. +The [fold](../creational/fold.md) pattern is similar to visitor but produces a +new version of the visited data structure. diff --git a/src/patterns/creational/builder.md b/src/patterns/creational/builder.md index 211ef376..cd40836a 100644 --- a/src/patterns/creational/builder.md +++ b/src/patterns/creational/builder.md @@ -62,8 +62,8 @@ fn builder_test() { ## Motivation -Useful when you would otherwise require many constructors or where -construction has side effects. +Useful when you would otherwise require many constructors or where construction +has side effects. ## Advantages @@ -88,8 +88,9 @@ Rust than in C++, Java, or others. This pattern is often used where the builder object is useful in its own right, rather than being just a builder. For example, see [`std::process::Command`](https://doc.rust-lang.org/std/process/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. +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. The example takes and returns the builder by value. It is often more ergonomic (and more efficient) to take and return the builder as a mutable reference. The @@ -108,8 +109,8 @@ as well as the `FooBuilder::new().a().b().build()` style. ## See also - [Description in the style guide](https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html) -- [derive_builder](https://crates.io/crates/derive_builder), a crate for automatically - implementing this pattern while avoiding the boilerplate. +- [derive_builder](https://crates.io/crates/derive_builder), a crate for + automatically implementing this pattern while avoiding the boilerplate. - [Constructor pattern](../../idioms/ctor.md) for when construction is simpler. - [Builder pattern (wikipedia)](https://en.wikipedia.org/wiki/Builder_pattern) - [Construction of complex values](https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder) diff --git a/src/patterns/creational/fold.md b/src/patterns/creational/fold.md index 13eab838..2874563f 100644 --- a/src/patterns/creational/fold.md +++ b/src/patterns/creational/fold.md @@ -5,9 +5,9 @@ Run an algorithm over each item in a collection of data to create a new item, thus creating a whole new collection. -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. +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. ## Example @@ -102,9 +102,9 @@ reused; however, a node must be cloned even if unchanged, which can be expensive. 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. +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. ## See also diff --git a/src/patterns/creational/intro.md b/src/patterns/creational/intro.md index 782fdc80..318e2bf6 100644 --- a/src/patterns/creational/intro.md +++ b/src/patterns/creational/intro.md @@ -2,7 +2,8 @@ From [Wikipedia](https://en.wikipedia.org/wiki/Creational_pattern): -> 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. +> 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. diff --git a/src/patterns/ffi/export.md b/src/patterns/ffi/export.md index f7d32608..a715e4bd 100644 --- a/src/patterns/ffi/export.md +++ b/src/patterns/ffi/export.md @@ -5,46 +5,51 @@ 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: -1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user, - and _opaque_. -2. All Transactional data types should be _owned_ by the user, and _transparent_. +1. All Encapsulated types should be *owned* by Rust, *managed* by the user, and + *opaque*. +2. All Transactional data types should be *owned* by the user, and + *transparent*. 3. All library behavior should be functions acting upon Encapsulated types. -4. All library behavior should be encapsulated into types not based on structure, - but _provenance/lifetime_. +4. All library behavior should be encapsulated into types not based on + structure, but *provenance/lifetime*. ## Motivation -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). +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). 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: +design in Rust as little as possible. There are three goals with any foreign +API: 1. Make it easy to use in the target language. -2. Avoid the API dictating internal unsafety on the Rust side as much as possible. -3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small - as possible. +2. Avoid the API dictating internal unsafety on the Rust side as much as + possible. +3. Keep the potential for memory unsafety and Rust `undefined behaviour` as + small as possible. 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`. +point. However, every bit of `unsafe` code on the Rust side is an opportunity +for bugs, or to exacerbate `undefined behaviour`. 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. -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`. +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`. ## Code Example -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). +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. 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. +involved in FFI. The commentary below should help explain it for those who miss +the subtleties. ```C struct DBM; @@ -63,50 +68,47 @@ int dbm_store(DBM *, datum, datum, int); This API defines two types: `DBM` and `datum`. -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. +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. 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_. - -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. - -The `datum` type was called a "transactional" type above. -It is designed to facilitate the exchange of information between the library and -its user. - -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. - -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`. - -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? - -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. - -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_. +only gives them *a pointer to one*. + +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. + +The `datum` type was called a "transactional" type above. It is designed to +facilitate the exchange of information between the library and its user. + +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. + +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`. + +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? + +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. + +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*. ## Advantages @@ -119,12 +121,12 @@ relatively small number: 3. The `dptr` on any `datum` must be `NULL`, or point to a valid slice of memory at the advertised length. -In addition, it avoids a lot of pointer provenance issues. -To understand why, let us consider an alternative in some depth: key iteration. +In addition, it avoids a lot of pointer provenance issues. To understand why, +let us consider an alternative in some depth: key iteration. -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. +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. Here is how iteration would be done in Rust for `DBM`: @@ -144,8 +146,8 @@ struct DbmKeysIter<'it> { impl<'it> Iterator for DbmKeysIter<'it> { ... } ``` -This is clean, idiomatic, and safe. thanks to Rust's guarantees. -However, consider what a straightforward API translation would look like: +This is clean, idiomatic, and safe. thanks to Rust's guarantees. However, +consider what a straightforward API translation would look like: ```rust,ignore #[no_mangle] @@ -166,9 +168,9 @@ pub extern "C" fn dbm_iter_del(*mut DbmKeysIter) { ``` 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. +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. This example written in C contains a bug that will be explained afterwards: @@ -206,23 +208,23 @@ end-of-iteration marker: 2. The length is incremented, in this case by zero. 3. The if statement is true, so the database is closed. There should be a break statement here. -4. The loop condition executes again, causing a `next` call on the closed object. +4. The loop condition executes again, causing a `next` call on the closed + object. -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! +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! -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". +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". -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: +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: ```C datum dbm_firstkey(DBM *); @@ -236,25 +238,25 @@ Thus, all the lifetimes were bound together, and such unsafety was prevented. However, this design choice also has a number of drawbacks, which should be considered as well. -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. +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. -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: +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: -- [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types together - into an opaque "object" +- [Wrapper Type Consolidation](./wrappers.md) groups multiple Rust types + together into an opaque "object" -- [FFI Error Passing](../../idioms/ffi/errors.md) explains error handling with integer - codes and sentinel return values (such as `NULL` pointers) +- [FFI Error Passing](../../idioms/ffi/errors.md) explains error handling with + integer codes and sentinel return values (such as `NULL` pointers) -- [Accepting Foreign Strings](../../idioms/ffi/accepting-strings.md) allows accepting - strings with minimal unsafe code, and is easier to get right than +- [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) -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. +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. diff --git a/src/patterns/ffi/intro.md b/src/patterns/ffi/intro.md index a2e300fe..bc9bd596 100644 --- a/src/patterns/ffi/intro.md +++ b/src/patterns/ffi/intro.md @@ -1,13 +1,13 @@ # FFI Patterns -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. +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. This section contains design patterns that may be useful when doing FFI. -1. [Object-Based API](./export.md) design that has good memory safety characteristics, - and a clean boundary of what is safe and what is unsafe +1. [Object-Based API](./export.md) design that has good memory safety + characteristics, and a clean boundary of what is safe and what is unsafe 2. [Type Consolidation into Wrappers](./wrappers.md) - group multiple Rust types together into an opaque "object" diff --git a/src/patterns/ffi/wrappers.md b/src/patterns/ffi/wrappers.md index 13393ed5..68dadc33 100644 --- a/src/patterns/ffi/wrappers.md +++ b/src/patterns/ffi/wrappers.md @@ -5,33 +5,34 @@ This pattern is designed to allow gracefully handling multiple related types, while minimizing the surface area for memory unsafety. -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. +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. -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. +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. -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. +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. -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. +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. ## Code Example -To understand this, let us look at a classic example of an API to export: iteration -through a collection. +To understand this, let us look at a classic example of an API to export: +iteration through a collection. That API looks like this: 1. The iterator is initialized with `first_key`. 2. Each call to `next_key` will advance the iterator. 3. Calls to `next_key` if the iterator is at the end will do nothing. -4. As noted above, the iterator is "wrapped into" the collection (unlike the native - Rust API). +4. As noted above, the iterator is "wrapped into" the collection (unlike the + native Rust API). If the iterator implements `nth()` efficiently, then it is possible to make it ephemeral to each function call: @@ -62,19 +63,19 @@ As a result, the wrapper is simple and contains no `unsafe` code. ## Advantages -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. +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. ## Disadvantages Often, wrapping types is quite difficult, and sometimes a Rust API compromise would make things easier. -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. +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. ### Trying to Wrap Iterators (and Failing) @@ -82,9 +83,9 @@ 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. -Suffice it to say, this is _incredibly_ difficult. +Suffice it to say, this is *incredibly* difficult. -Here is an illustration of just _one_ pitfall. +Here is an illustration of just *one* pitfall. A first version of `MySetWrapper` would look like this: @@ -97,14 +98,13 @@ struct MySetWrapper { } ``` -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`_. +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`*. -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. +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. A simple implementation of `myset_store` would be: @@ -134,29 +134,30 @@ pub mod unsafe_module { } ``` -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] - -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. - -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) +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] + +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. + +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! 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. +optimizations that C code cannot attain. Being denied access to certain +shortcuts is the price Rust programmers need to pay. [^1]: For the C programmers out there scratching their heads, the iterator need -not be read _during_ this code 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. +not be read *during* this code 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. diff --git a/src/patterns/index.md b/src/patterns/index.md index 1718174c..87c40c31 100644 --- a/src/patterns/index.md +++ b/src/patterns/index.md @@ -14,15 +14,17 @@ about a programming language. ## Design patterns in Rust Rust has many unique features. These features give us great benefit by removing -whole classes of problems. Some of them are also patterns that are _unique_ to Rust. +whole classes of problems. Some of them are also patterns that are *unique* to +Rust. ## YAGNI -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. +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. > The best code I ever wrote was code I never wrote. -If we apply YAGNI to design patterns, we see that the features of Rust allow 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). +If we apply YAGNI to design patterns, we see that the features of Rust allow 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). diff --git a/src/patterns/structural/intro.md b/src/patterns/structural/intro.md index 34d9cc9b..d0f0c60d 100644 --- a/src/patterns/structural/intro.md +++ b/src/patterns/structural/intro.md @@ -2,5 +2,5 @@ From [Wikipedia](https://en.wikipedia.org/wiki/Structural_pattern): -> Design patterns that ease the design by identifying a simple way to realize relationships -> among entities. +> Design patterns that ease the design by identifying a simple way to realize +> relationships among entities. diff --git a/src/patterns/structural/small-crates.md b/src/patterns/structural/small-crates.md index c652fc20..a95eb0a1 100644 --- a/src/patterns/structural/small-crates.md +++ b/src/patterns/structural/small-crates.md @@ -5,27 +5,27 @@ Prefer small crates that do one thing well. 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. +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. ## Advantages - Small crates are easier to understand, and encourage more modular code. -- 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. -- 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. +- 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. +- 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. ## Disadvantages -- 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`. +- 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`. - Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious. - Two small crates may be less optimized than one large one, since the compiler diff --git a/src/patterns/structural/unsafe-mods.md b/src/patterns/structural/unsafe-mods.md index c59463b0..76a7a667 100644 --- a/src/patterns/structural/unsafe-mods.md +++ b/src/patterns/structural/unsafe-mods.md @@ -6,7 +6,8 @@ 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. +that call directly into the unsafe code. Users may use this to gain speed +benefits. ## Advantages @@ -21,13 +22,13 @@ that call directly into the unsafe code. Users may use this to gain speed benefi ## Examples -- The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations - in submodules, presenting a safe interface to users. +- The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe + operations in submodules, presenting a safe interface to users. - `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. + 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. ## See also diff --git a/src/refactoring/index.md b/src/refactoring/index.md index 178a53b0..63c893fc 100644 --- a/src/refactoring/index.md +++ b/src/refactoring/index.md @@ -1,12 +1,13 @@ # Refactoring -Refactoring is very important in relation to these topics. -Just as important as the other topics covered here, is how to take good code and -turn it into great code. - -We can use [design patterns](../patterns/index.md) to [DRY] up code and generalize -abstractions. We must avoid [anti-patterns](../anti_patterns/index.md) while we -do this. While they may be tempting to employ, their costs outweigh their benefits. +Refactoring is very important in relation to these topics. Just as important as +the other topics covered here, is how to take good code and turn it into great +code. + +We can use [design patterns](../patterns/index.md) to [DRY] up code and +generalize abstractions. We must avoid +[anti-patterns](../anti_patterns/index.md) while we do this. While they may be +tempting to employ, their costs outweigh their benefits. > Shortcuts make for long days. diff --git a/src/translations.md b/src/translations.md index 8d5697b8..786d6189 100644 --- a/src/translations.md +++ b/src/translations.md @@ -1,7 +1,9 @@ # Translations -We are utilizing [mdbook-i18n-helper](https://github.com/google/mdbook-i18n-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) +We are utilizing +[mdbook-i18n-helper](https://github.com/google/mdbook-i18n-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) ## External translations diff --git a/template.md b/template.md index f5f65015..098dda40 100644 --- a/template.md +++ b/template.md @@ -12,8 +12,8 @@ A short, prose description of the pattern. ``` When writing examples, please try to make them compile. This allows us to test -them. If you fail to write an example that is both complete and readable, -please at least mark your example code with `ignore` as in here: +them. If you fail to write an example that is both complete and readable, please +at least mark your example code with `ignore` as in here: ```rust,ignore // A non-runnable example of the pattern in action, should be mostly code, commented From 0a12425a6478f243fcc0e6b10de707fc919aa62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Gonz=C3=A1lez?= Date: Tue, 22 Aug 2023 22:05:23 +0200 Subject: [PATCH 176/217] fix: correct typos in mem-replace.md (#371) * fix: fix typos in mem-replace.md --- src/idioms/mem-replace.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/idioms/mem-replace.md b/src/idioms/mem-replace.md index ab2d431e..28d0d27a 100644 --- a/src/idioms/mem-replace.md +++ b/src/idioms/mem-replace.md @@ -20,7 +20,7 @@ enum MyEnum { fn a_to_b(e: &mut MyEnum) { if let MyEnum::A { name, x: 0 } = e { - // this takes out our `name` and put in an empty String instead + // This takes out our `name` and puts in an empty String instead // (note that empty strings don't allocate). // Then, construct the new enum variant (which will // be assigned to `*e`). @@ -69,8 +69,8 @@ into our `MyEnum::B`, but that would be an instance of the anti-pattern. Anyway, we can avoid the extra allocation by changing `e` with only a mutable borrow. -`mem::take` lets us swap out the value, replacing it with it's default value, -and returning the previous value. For `String`, the default value is an empty +`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 `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. From bbcf07985d4aecf01663071a89768964adf37004 Mon Sep 17 00:00:00 2001 From: jhwgh1968 Date: Mon, 28 Aug 2023 23:05:16 +0000 Subject: [PATCH 177/217] Iteration on Functional optics (#364) Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> Co-authored-by: Julian Ganz --- src/SUMMARY.md | 2 +- src/functional/lenses.md | 355 --------------------------- src/functional/optics.md | 507 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 508 insertions(+), 356 deletions(-) delete mode 100644 src/functional/lenses.md create mode 100644 src/functional/optics.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c2771940..01a4c728 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -49,7 +49,7 @@ - [Functional Programming](./functional/index.md) - [Programming paradigms](./functional/paradigms.md) - [Generics as Type Classes](./functional/generics-type-classes.md) - - [Lenses and Prisms](./functional/lenses.md) + - [Functional Optics](./functional/optics.md) - [Additional Resources](./additional_resources/index.md) - [Design principles](./additional_resources/design-principles.md) diff --git a/src/functional/lenses.md b/src/functional/lenses.md deleted file mode 100644 index d38354b6..00000000 --- a/src/functional/lenses.md +++ /dev/null @@ -1,355 +0,0 @@ -# Lenses and Prisms - -This is a pure functional concept that is not frequently used in Rust. -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. - -## Lenses: Uniform Access Across Types - -A lens is a concept from functional programming languages that allows accessing -parts of a data type in an abstract, unified way.[^1] In basic concept, it is -similar to the way Rust traits work with type erasure, but it has a bit more -power and flexibility. - -For example, suppose a bank contains several JSON formats for customer data. -This is because they come from different databases or legacy systems. One -database contains the data needed to perform credit checks: - -```json -{ "name": "Jane Doe", - "dob": "2002-02-24", - [...] - "customer_id": 1048576332, -} -``` - -Another one contains the account information: - -```json -{ "customer_id": 1048576332, - "accounts": [ - { "account_id": 2121, - "account_type: "savings", - "joint_customer_ids": [], - [...] - }, - { "account_id": 2122, - "account_type: "checking", - "joint_customer_ids": [1048576333], - [...] - }, - ] -} -``` - -Notice that both types have a customer ID number which corresponds to a person. -How would a single function handle both records of different types? - -In Rust, a `struct` could represent each of these types, and a trait would have -a `get_customer_id` function they would implement: - -```rust -use std::collections::HashSet; - -pub struct Account { - account_id: u32, - account_type: String, - // other fields omitted -} - -pub trait CustomerId { - fn get_customer_id(&self) -> u64; -} - -pub struct CreditRecord { - customer_id: u64, - name: String, - dob: String, - // other fields omitted -} - -impl CustomerId for CreditRecord { - fn get_customer_id(&self) -> u64 { - self.customer_id - } -} - -pub struct AccountRecord { - customer_id: u64, - accounts: Vec, -} - -impl CustomerId for AccountRecord { - fn get_customer_id(&self) -> u64 { - self.customer_id - } -} - -// static polymorphism: only one type, but each function call can choose it -fn unique_ids_set(records: &[R]) -> HashSet { - records.iter().map(|r| r.get_customer_id()).collect() -} - -// dynamic dispatch: iterates over any type with a customer ID, collecting all -// values together -fn unique_ids_iter(iterator: I) -> HashSet - where I: Iterator> -{ - iterator.map(|r| r.as_ref().get_customer_id()).collect() -} -``` - -Lenses, however, allow the code supporting customer ID to be moved from the -*type* to the *accessor function*. Rather than implementing a trait on each -type, all matching structures can simply be accessed the same way. - -While the Rust language itself does not support this (type erasure is the -preferred solution to this problem), the -[lens-rs crate](https://github.com/TOETOE55/lens-rs/blob/master/guide.md) allows -code that feels like this to be written with macros: - -```rust,ignore -use std::collections::HashSet; - -use lens_rs::{optics, Lens, LensRef, Optics}; - -#[derive(Clone, Debug, Lens /* derive to allow lenses to work */)] -pub struct CreditRecord { - #[optic(ref)] // macro attribute to allow viewing this field - customer_id: u64, - name: String, - dob: String, - // other fields omitted -} - -#[derive(Clone, Debug)] -pub struct Account { - account_id: u32, - account_type: String, - // other fields omitted -} - -#[derive(Clone, Debug, Lens)] -pub struct AccountRecord { - #[optic(ref)] - customer_id: u64, - accounts: Vec, -} - -fn unique_ids_lens(iter: impl Iterator) -> HashSet -where - T: LensRef, // any type with this field -{ - iter.map(|r| *r.view_ref(optics!(customer_id))).collect() -} -``` - -The version of `unique_ids_lens` shown here allows any type to be in the -iterator, so long as it has an attribute called `customer_id` which can be -accessed by the function. This is how most functional programming languages -operate on lenses. - -Rather than macros, they achieve this with a technique known as "currying". That -is, they "partially construct" the function, leaving the type of the final -parameter (the value being operated on) unfilled until the function is called. -Thus it can be called with different types dynamically even from one place in -the code. That is what the `optics!` and `view_ref` in the example above -simulates. - -The functional approach need not be restricted to accessing members. More -powerful lenses can be created which both *set* and *get* data in a structure. -But the concept really becomes interesting when used as a building block for -composition. That is where the concept appears more clearly in Rust. - -## Prisms: A Higher-Order form of "Optics" - -A simple function such as `unique_ids_lens` above operates on a single lens. A -*prism* is a function that operates on a *family* of lenses. It is one -conceptual level higher, using lenses as a building block, and continuing the -metaphor, is part of a family of "optics". It is the main one that is useful in -understanding Rust APIs, so will be the focus here. - -The same way that traits allow "lens-like" design with static polymorphism and -dynamic dispatch, prism-like designs appear in Rust APIs which split problems -into multiple associated types to be composed. A good example of this is the -traits in the parsing crate *Serde*. - -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 some type in any library which parses a new format: - -```rust,ignore -pub trait Deserializer<'de>: Sized { - type Error: Error; - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>; - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>; - - // remainder ommitted -} -``` - -For a trait that is just supposed to parse data from a format and return a -value, this looks odd. - -Why are all the return types type erased? - -To understand that, we need to keep the lens concept in mind and look at the -definition of the `Visitor` type that is passed in generically: - -```rust,ignore -pub trait Visitor<'de>: Sized { - type Value; - - fn visit_bool(self, v: bool) -> Result - where - E: Error; - - fn visit_u64(self, v: u64) -> Result - where - E: Error; - - fn visit_str(self, v: &str) -> Result - where - E: Error; - - // remainder omitted -} -``` - -The job of the `Visitor` type is to construct values in the *Serde* data model, -which are represented by its associated `Value` type. - -These values represent parts of the Rust value being deserialized. If this -fails, it returns an `Error` type - an error type determined by the -`Deserializer` when its methods were called. - -This highlights that `Deserializer` is similar to `CustomerId` from earlier, -allowing any format parser which implements it to create `Value`s based on what -it parsed. The `Value` trait is acting like a lens in functional programming -languages. - -But unlike the `CustomerId` trait, the return types of `Visitor` methods are -*generic*, and the concrete `Value` type is *determined by the Visitor itself*. - -Instead of acting as one lens, it effectively acts as a family of lenses, one -for each concrete type of `Visitor`. - -The `Deserializer` API is based on having a generic set of "lenses" work across -a set of other generic types for "observation". It is a *prism*. - -For example, consider the identity record from earlier but simplified: - -```json -{ "name": "Jane Doe", "customer_id": 1048576332 } -``` - -How would the *Serde* library deserialize this JSON into `struct CreditRecord`? - -1. The user would call a library function to deserialize the data. This would - create a `Deserializer` based on the JSON format. -1. 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: `u64` and `String`. -1. The deserializer would make calls to the `Visitor` as it parsed items. -1. The `Visitor` would indicate if the items found were expected, and if not, - raise an error to indicate deserialization has failed. - -For our very simple structure above, the expected pattern would be: - -1. Visit a map (*Serde*'s equvialent to `HashMap` or JSON's dictionary). -1. Visit a string key called "name". -1. Visit a string value, which will go into the `name` field. -1. Visit a string key called "customer_id". -1. Visit a string value, which will go into the `customer_id` field. -1. Visit the end of the map. - -But what determines which "observation" pattern is expected? - -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. - -*Serde* solves this usability challenge with a derive macro: - -```rust,ignore -use serde::Deserialize; - -#[derive(Deserialize)] -struct IdRecord { - name: String, - customer_id: String, -} -``` - -That macro simply generates an impl block causing the struct to implement a -trait called `Deserialize`. - -It is defined this way: - -```rust,ignore -pub trait Deserialize<'de>: Sized { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>; -} -``` - -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. - -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. - -For a complete example, see the -[*Serde* documentation](https://serde.rs/deserialize-struct.html). - -To wrap up, this is the power of *Serde*: - -1. The structure being parsed is represented by an `impl` block for - `Deserialize` -1. The input data format (e.g. JSON) is represented by a `Deserializer` called - by `Deserialize` -1. The `Deserializer` acts like a prism which "refracts" lens-like `Visitor` - calls which actually build the data value - -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. - -To emphasize, the only reason this model works on any format and any type is -because the `Deserializer` trait's output type **is specified by the implementor -of `Visitor` it is passed**, rather than being tied to one specific type. This -was not true in the account example earlier. - -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. - -## See Also - -- [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses - implementation, with a cleaner interface than these examples -- [serde](https://serde.rs) itself, which makes these concepts intuitive for end - users (i.e. defining the structs) without needing to undestand the details -- [luminance](https://github.com/phaazon/luminance-rs) is a crate for drawing - computer graphics that uses lens API design, including proceducal macros to - create full prisms for buffers of different pixel types that remain generic -- [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. -- [Paper: Profunctor Optics: Modular Data - Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf) - -[^1]: [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) diff --git a/src/functional/optics.md b/src/functional/optics.md new file mode 100644 index 00000000..e281a00d --- /dev/null +++ b/src/functional/optics.md @@ -0,0 +1,507 @@ +# Functional Language Optics + +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. + +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. + +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. + +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 to understand from simply +the API documentation. + +In the process, different specific patterns, called Optics, will be covered. +These are *The Iso*, *The Poly Iso*, and *The Prism*. + +## An API Example: Serde + +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: + +```rust,ignore +pub trait Deserializer<'de>: Sized { + type Error: Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>; + + // remainder omitted +} +``` + +And here's the definition of the `Visitor` trait passed in generically: + +```rust,ignore +pub trait Visitor<'de>: Sized { + type Value; + + fn visit_bool(self, v: bool) -> Result + where + E: Error; + + fn visit_u64(self, v: u64) -> Result + where + E: Error; + + fn visit_str(self, v: &str) -> Result + where + E: Error; + + // remainder omitted +} +``` + +There is a lot of type erasure going on here, with multiple levels of associated +types being passed back and forth. + +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? + +One way to understand it is to look at a functional languages concept called +*optics*. + +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] + +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. + +This will perhaps shed light on what those APIs are achieving: specific +properties of composability. + +## Basic Optics + +### The Iso + +The Iso is a value transformer between two types. It is extremely simple, but a +conceptually important building block. + +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). + +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.) + +To write it in a normal form expected by functional language users: + +```text +case class ConcordanceSerDe { + serialize: Concordance -> String + deserialize: String -> Concordance +} +``` + +The Iso is thus a pair of functions which convert values of different types: +`serialize` and `deserialize`. + +A straightforward implementation: + +```rust +use std::collections::HashMap; + +struct Concordance { + keys: HashMap, + value_table: Vec<(usize, usize)>, +} + +struct ConcordanceSerde {} + +impl ConcordanceSerde { + fn serialize(value: Concordance) -> String { + todo!() + } + // invalid concordances are empty + fn deserialize(value: String) -> Concordance { + todo!() + } +} +``` + +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. + +But that is where our next subject comes in: Poly Isos. + +### Poly Isos + +The previous example was simply converting between values of two fixed types. +This next block builds upon it with generics, and is more interesting. + +Poly Isos allow an operation to be generic over any type while returning a +single type. + +This brings us closer to parsing. Consider what a basic parser would do ignoring +error cases. Again, this is its normal form: + +```text +case class Serde[T] { + deserialize(String) -> T + serialize(T) -> String +} +``` + +Here we have our first generic, the type `T` being converted. + +In Rust, this could be implemented with a pair of traits in the standard +library: `FromStr` and `ToString`. The Rust version even handles errors: + +```rust,ignore +pub trait FromStr: Sized { + type Err; + + fn from_str(s: &str) -> Result; +} + +pub trait ToString { + fn to_string(&self) -> String; +} +``` + +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. + +At first glance, this seems like a good option for writing a parser. Let's see +it in action: + +```rust,ignore +use anyhow; + +use std::str::FromStr; + +struct TestStruct { + a: usize, + b: String, +} + +impl FromStr for TestStruct { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + todo!() + } +} + +impl ToString for TestStruct { + fn to_string(&self) -> String { + todo!() + } +} + +fn main() { + let a = TestStruct { a: 5, b: "hello".to_string() }; + println!("Our Test Struct as JSON: {}", a.to_string()); +} +``` + +That seems quite logical. However, there are two problems with this. + +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. + +But there is a second, subtler problem: scaling. + +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! + +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`. + +This means, in normal form (again, skipping error handling for simplicity): + +```text +case class Serde[T] { + deserialize: Visitor[T] -> T + serialize: T -> Visitor[T] +} + +case class Visitor[T] { + toJson: Visitor[T] -> String + fromJson: String -> Visitor[T] +} +``` + +The result is one Poly Iso and one Iso (respectively). Both of these can be +implemented with traits: + +```rust +trait Serde { + type V; + fn deserialize(visitor: Self::V) -> Self; + fn serialize(self) -> Self::V; +} + +trait Visitor { + fn to_json(self) -> String; + fn from_json(json: String) -> Self; +} +``` + +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`: + +```rust,ignore +#[derive(Default, Serde)] // the "Serde" derive creates the trait impl block +struct TestStruct { + a: usize, + b: String, +} + +// user writes this macro to generate an associated visitor type +generate_visitor!(TestStruct); +``` + +Or do they? + +```rust,ignore +fn main() { + let a = TestStruct { a: 5, b: "hello".to_string() }; + let a_data = a.serialize().to_json(); + println!("Our Test Struct as JSON: {}", a_data); + let b = TestStruct::deserialize( + generated_visitor_for!(TestStruct)::from_json(a_data)); +} +``` + +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. + +It's wonky, but it works... until we get to the elephant in the room. + +The only format currently supported is JSON. How would we support more formats? + +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! + +In order to solve that, we need something more powerful. + +## Prism + +To take format into account, we need something in normal form like this: + +```text +case class Serde[T, F] { + serialize: T, F -> String + deserialize: String, F -> Result[T, Error] +} +``` + +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). + +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. + +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. + +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. + +In normal form: + +```text +case class Serde[T] { + serialize: F -> String + deserialize F, String -> Result[T, Error] +} + +case class VisitorForT { + build: F, String -> Result[T, Error] + decompose: F, T -> String +} + +case class SerdeFormat[T, V] { + toString: T, V -> String + fromString: V, String -> Result[T, Error] +} +``` + +And what do you know, a pair of Poly Isos at the bottom which can be implemented +as traits! + +Thus we have the Serde API: + +1. Each type to be serialized implements `Deserialize` or `Serialize`, + equivalent to the `Serde` class +1. 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. +1. The type implementing the `Deserializer` trait handles all details specific + to the format, being "driven by" the `Visitor`. + +This splitting and Rust type erasure is really to achieve a Prism through +indirection. + +You can see it on the `Deserializer` trait + +```rust,ignore +pub trait Deserializer<'de>: Sized { + type Error: Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>; + + // remainder omitted +} +``` + +And the visitor: + +```rust,ignore +pub trait Visitor<'de>: Sized { + type Value; + + fn visit_bool(self, v: bool) -> Result + where + E: Error; + + fn visit_u64(self, v: u64) -> Result + where + E: Error; + + fn visit_str(self, v: &str) -> Result + where + E: Error; + + // remainder omitted +} +``` + +And the trait `Deserialize` implemented by the macros: + +```rust,ignore +pub trait Deserialize<'de>: Sized { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; +} +``` + +This has been abstract, so let's look at a concrete example. + +How does actual Serde deserialize a bit of JSON into `struct Concordance` from +earlier? + +1. The user would call a library function to deserialize the data. This would + create a `Deserializer` based on the JSON format. +1. 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`. +1. The deserializer would make calls to the `Visitor` as it parsed items. +1. The `Visitor` would indicate if the items found were expected, and if not, + raise an error to indicate deserialization has failed. + +For our very simple structure above, the expected pattern would be: + +1. Begin visiting a map (*Serde*'s equivalent to `HashMap` or JSON's + dictionary). +1. Visit a string key called "keys". +1. Begin visiting a map value. +1. For each item, visit a string key then an integer value. +1. Visit the end of the map. +1. Store the map into the `keys` field of the data structure. +1. Visit a string key called "value_table". +1. Begin visiting a list value. +1. For each item, visit an integer. +1. Visit the end of the list +1. Store the list into the `value_table` field. +1. Visit the end of the map. + +But what determines which "observation" pattern is expected? + +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. + +*Serde* solves this usability challenge with a derive macro: + +```rust,ignore +use serde::Deserialize; + +#[derive(Deserialize)] +struct IdRecord { + name: String, + customer_id: String, +} +``` + +That macro simply generates an impl block causing the struct to implement a +trait called `Deserialize`. + +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. + +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. + +For a complete example, see the +[*Serde* documentation](https://serde.rs/deserialize-struct.html). + +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. + +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. + +If you are interested in learning more about this topic, please check the +following section. + +## See Also + +- [lens-rs crate](https://crates.io/crates/lens-rs) for a pre-built lenses + implementation, with a cleaner interface than these examples +- [Serde](https://serde.rs) itself, which makes these concepts intuitive for end + users (i.e. defining the structs) without needing to understand the details +- [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 +- [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. +- [Paper: Profunctor Optics: Modular Data + Accessors](https://web.archive.org/web/20220701102832/https://arxiv.org/ftp/arxiv/papers/1703/1703.10857.pdf) +- [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 + +[^1]: [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) + +[^2]: [Concordance on Wikipedia](https://en.wikipedia.org/wiki/Concordance_(publishing)) From 71b3aa60d077c5fb2f088d07f2ca1c1c11a7c3e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 01:11:58 +0200 Subject: [PATCH 178/217] Bump actions/checkout from 3 to 4 (#373) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 8 ++++---- .github/workflows/lint.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/url-check-on-change.yml | 2 +- .github/workflows/url-check-periodic.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ae13022..f6eda01d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Rust cache uses: ./.github/workflows/setup-rust-cache @@ -30,7 +30,7 @@ jobs: # runs-on: ubuntu-latest # steps: # - name: Checkout - # uses: actions/checkout@v3 + # uses: actions/checkout@v4 # - name: Install Gettext # run: sudo apt install gettext @@ -69,7 +69,7 @@ jobs: # languages: ${{ steps.find-translations.outputs.languages }} # steps: # - name: Checkout - # uses: actions/checkout@v3 + # uses: actions/checkout@v4 # - name: Find translations # id: find-translations @@ -92,7 +92,7 @@ jobs: # MDBOOK_BOOK__LANGUAGE: ${{ matrix.language }} # steps: # - name: Checkout - # uses: actions/checkout@v3 + # uses: actions/checkout@v4 # - name: Install Gettext # run: sudo apt install gettext diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bf2ee6e5..df583975 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,6 +9,6 @@ jobs: style: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dprint/check@v2.2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2b04282a..d1607f3d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Rust cache uses: ./.github/workflows/setup-rust-cache diff --git a/.github/workflows/url-check-on-change.yml b/.github/workflows/url-check-on-change.yml index c3c571d6..fe4cfb66 100644 --- a/.github/workflows/url-check-on-change.yml +++ b/.github/workflows/url-check-on-change.yml @@ -9,7 +9,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: use-verbose-mode: 'yes' diff --git a/.github/workflows/url-check-periodic.yml b/.github/workflows/url-check-periodic.yml index e5d7c075..00ca9e3b 100644 --- a/.github/workflows/url-check-periodic.yml +++ b/.github/workflows/url-check-periodic.yml @@ -9,7 +9,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: use-verbose-mode: 'yes' From 3a8277271901975f369d29025e4471564cb01d3e Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:25:45 +0200 Subject: [PATCH 179/217] feat(strategy): add link to blog post about application of strategy pattern (#374) --- src/patterns/behavioural/strategy.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/patterns/behavioural/strategy.md b/src/patterns/behavioural/strategy.md index 92c0a7a3..f80ea4b6 100644 --- a/src/patterns/behavioural/strategy.md +++ b/src/patterns/behavioural/strategy.md @@ -180,3 +180,4 @@ fn main() { - [Strategy Pattern](https://en.wikipedia.org/wiki/Strategy_pattern) - [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) - [Policy Based Design](https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design) +- [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/) From 675591b4ef511d37b003da209dcbbaf7bc4a065c Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:45:54 +0200 Subject: [PATCH 180/217] ci: update workflows (#375) --- .env | 4 ++-- .github/workflows/install-mdbook/action.yml | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.env b/.env index 234d3292..6c574267 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -MDBOOK_VERSION=0.4.28 -MDBOOK_I18N_HELPERS_VERSION=0.1.0 +MDBOOK_VERSION=0.4.35 +MDBOOK_I18N_HELPERS_VERSION=0.2.4 diff --git a/.github/workflows/install-mdbook/action.yml b/.github/workflows/install-mdbook/action.yml index e6d46298..e1482c35 100644 --- a/.github/workflows/install-mdbook/action.yml +++ b/.github/workflows/install-mdbook/action.yml @@ -9,21 +9,21 @@ runs: id: mdbook-version run: | . ./.env - echo "::set-output name=MDBOOK_VERSION::${MDBOOK_VERSION}" + echo "version=$MDBOOK_VERSION" >> $GITHUB_OUTPUT shell: bash - name: Read mdbook-i18n-helpers version from .env id: mdbook-i18n-helpers-version run: | . ./.env - echo "::set-output name=MDBOOK_I18N_HELPERS_VERSION::${MDBOOK_I18N_HELPERS_VERSION}" + echo "version=$MDBOOK_I18N_HELPERS_VERSION" >> $GITHUB_OUTPUT shell: bash - # The --locked flag is important for reproducible builds. - name: Install mdbook - run: cargo install mdbook --locked --version '${{ steps.mdbook-version.outputs.MDBOOK_VERSION }}' - shell: bash + uses: taiki-e/install-action@2afb713f1c297f70eecb9cb904b36612eba3c25e # v2 + with: + tool: mdbook@${{ steps.mdbook-version.outputs.version }} - name: Install i18n-helpers - run: cargo install mdbook-i18n-helpers --locked --version '${{ steps.mdbook-i18n-helpers-version.outputs.MDBOOK_I18N_HELPERS_VERSION }}' + run: cargo install mdbook-i18n-helpers --locked --version '${{ steps.mdbook-i18n-helpers-version.outputs.version }}' shell: bash From 79467dc4480fd93c85596d4a7bd18160527ce3e2 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:58:35 +0200 Subject: [PATCH 181/217] fix(theme): Fix side menu being stuck open and obscuring most of the page (#376) --- book.toml | 7 +- .../css/language-picker.css | 5 + theme/head.hbs | 26 + theme/index.hbs | 363 +++-- third_party/mdbook/book.js | 1312 +++++++++-------- 5 files changed, 930 insertions(+), 783 deletions(-) rename language-picker.css => theme/css/language-picker.css (59%) create mode 100644 theme/head.hbs diff --git a/book.toml b/book.toml index f2bf36d9..b68ec0c0 100644 --- a/book.toml +++ b/book.toml @@ -23,7 +23,7 @@ site-url = "/patterns/" git-repository-url = "https://github.com/rust-unofficial/patterns" git-repository-icon = "fa-github" edit-url-template = "https://github.com/rust-unofficial/patterns/edit/main/{path}" -additional-css = ["./language-picker.css"] +additional-css = ["theme/css/language-picker.css"] [output.html.fold] enable = true @@ -33,3 +33,8 @@ level = 1 editable = false # [output.linkcheck] # enable the "mdbook-linkcheck" renderer, disabled due to gh-actions + +[output.html.redirect] +# Redirects in the form of "old-path" = "new-path", where the new path +# is relative to the old path. +"functional/lenses.html" = "optics.html" diff --git a/language-picker.css b/theme/css/language-picker.css similarity index 59% rename from language-picker.css rename to theme/css/language-picker.css index 1f7d5377..1553ed68 100644 --- a/language-picker.css +++ b/theme/css/language-picker.css @@ -3,6 +3,11 @@ right: 10px; } +[dir="rtl"] #language-list { + left: 10px; + right: auto; +} + #language-list a { color: inherit; } diff --git a/theme/head.hbs b/theme/head.hbs new file mode 100644 index 00000000..8432ff2e --- /dev/null +++ b/theme/head.hbs @@ -0,0 +1,26 @@ +{{! Move to template code after fixing this issue: +https://github.com/google/mdbook-i18n-helpers/issues/70 }} + \ No newline at end of file diff --git a/theme/index.hbs b/theme/index.hbs index dd83020b..30c42d99 100644 --- a/theme/index.hbs +++ b/theme/index.hbs @@ -1,58 +1,63 @@ - - - - - {{ title }} - {{#if is_print }} - - {{/if}} - {{#if base_url}} - - {{/if}} - - - {{> head}} - - - - - - {{#if favicon_svg}} - - {{/if}} - {{#if favicon_png}} - - {{/if}} - - - - {{#if print_enable}} - - {{/if}} - - - - {{#if copy_fonts}} - - {{/if}} - - - - - - - - {{#each additional_css}} - - {{/each}} - - {{#if mathjax_support}} - - - {{/if}} - - + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + +

+ + + + +
{{> header}} -