mirror of
https://github.com/google/comprehensive-rust.git
synced 2024-11-28 18:11:07 +02:00
pt-BR: Some updates and fixes (#994)
pt-BR: Some updates and fixes to the Brazilian Portuguese translation.
This commit is contained in:
parent
2f86a259b6
commit
b0380e1f0e
429
po/pt-BR.po
429
po/pt-BR.po
@ -2,7 +2,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Comprehensive Rust 🦀\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2023-07-13 16:10-0700\n"
|
||||
"PO-Revision-Date: 2023-07-17 12:30-0700\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: pt_BR\n"
|
||||
@ -141,7 +141,7 @@ msgstr "Conversões Implícitas"
|
||||
|
||||
#: src/SUMMARY.md:39
|
||||
msgid "Arrays and for Loops"
|
||||
msgstr "Vetores e Laços For"
|
||||
msgstr "Matrizes e Loops for"
|
||||
|
||||
#: src/SUMMARY.md:41
|
||||
msgid "Day 1: Afternoon"
|
||||
@ -185,11 +185,11 @@ msgstr "Gerenciamento de Memória Baseado em Escopo"
|
||||
|
||||
#: src/SUMMARY.md:52
|
||||
msgid "Garbage Collection"
|
||||
msgstr "Garbage Collection (Coletor de lixo)"
|
||||
msgstr "Gerenciamento Automático de Memória"
|
||||
|
||||
#: src/SUMMARY.md:53
|
||||
msgid "Rust Memory Management"
|
||||
msgstr "Gerenciamento de Memória do Rust"
|
||||
msgstr "Gerenciamento de Memória no Rust"
|
||||
|
||||
#: src/SUMMARY.md:54
|
||||
msgid "Comparison"
|
||||
@ -201,7 +201,7 @@ msgstr "Ownership"
|
||||
|
||||
#: src/SUMMARY.md:56
|
||||
msgid "Move Semantics"
|
||||
msgstr "Semântica do move (mover)"
|
||||
msgstr "Semântica do Move (mover)"
|
||||
|
||||
#: src/SUMMARY.md:57
|
||||
msgid "Moved Strings in Rust"
|
||||
@ -257,7 +257,7 @@ msgstr "Structs"
|
||||
|
||||
#: src/SUMMARY.md:77
|
||||
msgid "Tuple Structs"
|
||||
msgstr "Structs como Tuplas"
|
||||
msgstr "Estruturas de Tuplas (Tuple Structs)"
|
||||
|
||||
#: src/SUMMARY.md:78
|
||||
msgid "Field Shorthand Syntax"
|
||||
@ -301,7 +301,7 @@ msgstr "Desestruturando Matrizes"
|
||||
|
||||
#: src/SUMMARY.md:89
|
||||
msgid "Match Guards"
|
||||
msgstr "Guardas de Correspondência (match)"
|
||||
msgstr "Guardas de Correspondência (Match Guards)"
|
||||
|
||||
#: src/SUMMARY.md:91
|
||||
msgid "Health Statistics"
|
||||
@ -3413,7 +3413,7 @@ msgid ""
|
||||
"* We create a slice by borrowing `a` and specifying the starting and ending "
|
||||
"indexes in brackets.\n"
|
||||
"\n"
|
||||
"* If the slice starts at index 0, Rust's range syntax allows us to drop the "
|
||||
"* If the slice starts at index 0, Rust’s range syntax allows us to drop the "
|
||||
"starting index, meaning that `&a[0..a.len()]` and `&a[..a.len()]` are "
|
||||
"identical.\n"
|
||||
" \n"
|
||||
@ -3490,10 +3490,10 @@ msgid ""
|
||||
msgstr ""
|
||||
"```rust,editable\n"
|
||||
"fn main() {\n"
|
||||
" let s1: &str = \"World\";\n"
|
||||
" let s1: &str = \"Mundo\";\n"
|
||||
" println!(\"s1: {s1}\");\n"
|
||||
"\n"
|
||||
" let mut s2: String = String::from(\"Hello \");\n"
|
||||
" let mut s2: String = String::from(\"Olá \");\n"
|
||||
" println!(\"s2: {s2}\");\n"
|
||||
" s2.push_str(s1);\n"
|
||||
" println!(\"s2: {s2}\");\n"
|
||||
@ -3615,6 +3615,33 @@ msgid ""
|
||||
"}\n"
|
||||
"```"
|
||||
msgstr ""
|
||||
"```rust,editable\n"
|
||||
"fn main() {\n"
|
||||
" imprimir_fizzbuzz_para(20);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn eh_divisivel(n: u32, divisor: u32) -> bool {\n"
|
||||
" if divisor == 0 {\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
" n % divisor == 0\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn fizzbuzz(n: u32) -> String {\n"
|
||||
" let fizz = if eh_divisivel(n, 3) { \"fizz\" } else { \"\" };\n"
|
||||
" let buzz = if eh_divisivel(n, 5) { \"buzz\" } else { \"\" };\n"
|
||||
" if fizz.is_empty() && buzz.is_empty() {\n"
|
||||
" return format!(\"{n}\");\n"
|
||||
" }\n"
|
||||
" format!(\"{fizz}{buzz}\")\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn imprimir_fizzbuzz_para(n: u32) {\n"
|
||||
" for i in 1..=n {\n"
|
||||
" println!(\"{}\", fizzbuzz(i));\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"```"
|
||||
|
||||
#: src/basic-syntax/functions.md:35
|
||||
msgid ""
|
||||
@ -3638,8 +3665,8 @@ msgstr ""
|
||||
"* Algumas funções não têm valor de retorno e retornam o 'tipo unitário', "
|
||||
"`()`. O compilador irá inferir isso se o tipo de retorno `-> ()` for "
|
||||
"omitido.\n"
|
||||
"* A expressão de intervalo no loop `for` em `fizzbuzz_to()` contém `=n`, o "
|
||||
"que faz com que inclua o limite superior."
|
||||
"* A expressão de intervalo no loop `for` em `imprimir_fizzbuzz_para()` "
|
||||
"contém `=n`, o que faz com que inclua o limite superior."
|
||||
|
||||
#: src/basic-syntax/rustdoc.md:1
|
||||
msgid "# Rustdoc"
|
||||
@ -3672,7 +3699,7 @@ msgstr ""
|
||||
"/// Determine se o primeiro argumento é divisível pelo segundo argumento.\n"
|
||||
"///\n"
|
||||
"/// Se o segundo argumento for zero, o resultado é falso.\n"
|
||||
"fn is_divisible_by(lhs: u32, rhs: u32) -> bool {\n"
|
||||
"fn divisivel_por(lhs: u32, rhs: u32) -> bool {\n"
|
||||
" if rhs == 0 {\n"
|
||||
" return false; // Caso excepcional, retorne antes\n"
|
||||
" }\n"
|
||||
@ -3895,7 +3922,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"* Conversões implícitas entre tipos.\n"
|
||||
"\n"
|
||||
"* Matrizes (_Arrays_) e laços (loops) `for`."
|
||||
"* Matrizes (_Arrays_) e _loops_ (laços) `for`."
|
||||
|
||||
#: src/exercises/day-1/morning.md:11
|
||||
msgid "A few things to consider while solving the exercises:"
|
||||
@ -4055,7 +4082,7 @@ msgstr ""
|
||||
|
||||
#: src/exercises/day-1/for-loops.md:1
|
||||
msgid "# Arrays and `for` Loops"
|
||||
msgstr "# Matrizes (Arrays) e Laços (Loops) `for`"
|
||||
msgstr "# Matrizes (_Arrays_) e _Loops_ (Laços) `for`"
|
||||
|
||||
#: src/exercises/day-1/for-loops.md:3
|
||||
msgid "We saw that an array can be declared like this:"
|
||||
@ -4429,7 +4456,8 @@ msgid ""
|
||||
"Globally-scoped names for values can be given with static variables and "
|
||||
"constant definitions."
|
||||
msgstr ""
|
||||
"Nomes com escopo global podem ser dados com variáveis estáticas e constantes."
|
||||
"Nomes com escopo global podem ser obtidos por meio de variáveis estáticas e "
|
||||
"definições de constantes."
|
||||
|
||||
#: src/basic-syntax/static-and-const.md:5
|
||||
msgid "## `const`"
|
||||
@ -4534,6 +4562,10 @@ msgid ""
|
||||
"Because `static` variables are accessible from any thread, mutable static "
|
||||
"variables require manual, unsafe, synchronization of accesses."
|
||||
msgstr ""
|
||||
"Nós iremos ver [dados estáticos mutáveis](../unsafe/mutable-static-variables."
|
||||
"md) no capítulo sobre Rust _inseguro_.\n"
|
||||
"Variáveis estáticas mutáveis são acessíveis por qualquer _thread_ e por isso "
|
||||
"necessitam de sincronização de acessos manual e insegura (_unsafe_)."
|
||||
|
||||
#: src/basic-syntax/static-and-const.md:50
|
||||
msgid ""
|
||||
@ -4836,8 +4868,8 @@ msgid ""
|
||||
"If not done with care, this can lead to crashes, bugs, security "
|
||||
"vulnerabilities, and memory leaks."
|
||||
msgstr ""
|
||||
"Se não for feito com cuidado, isso pode levar a travamentos, bugs, "
|
||||
"vulnerabilidades de segurança e vazamentos de memória."
|
||||
"Se isto não for feito com cuidado, travamentos, bugs, vulnerabilidades de "
|
||||
"segurança e vazamentos de memória podem ocorrer."
|
||||
|
||||
#: src/memory-management/manual.md:7
|
||||
msgid "## C Example"
|
||||
@ -5035,8 +5067,7 @@ msgstr ""
|
||||
|
||||
#: src/memory-management/rust.md:10
|
||||
msgid "Rust achieves this by modeling _ownership_ explicitly."
|
||||
msgstr ""
|
||||
"O Rust consegue isso modelando a propriedade (_ownership_) explicitamente."
|
||||
msgstr "O Rust consegue isso modelando o _ownership_ (posse) explicitamente."
|
||||
|
||||
#: src/memory-management/rust.md:14
|
||||
msgid ""
|
||||
@ -5185,7 +5216,7 @@ msgstr "# Semântica do `Move` (Mover)"
|
||||
|
||||
#: src/ownership/move-semantics.md:3
|
||||
msgid "An assignment will transfer ownership between variables:"
|
||||
msgstr "Uma atribuição transferirá a _ownership_ entre variáveis:"
|
||||
msgstr "Uma atribuição transferirá o _ownership_ entre variáveis:"
|
||||
|
||||
#: src/ownership/move-semantics.md:5
|
||||
msgid ""
|
||||
@ -5215,7 +5246,7 @@ msgid ""
|
||||
"* When `s2` goes out of scope, the string data is freed.\n"
|
||||
"* There is always _exactly_ one variable binding which owns a value."
|
||||
msgstr ""
|
||||
"* A atribuição de `s1` a `s2` transfere a _ownership_.\n"
|
||||
"* A atribuição de `s1` a `s2` transfere o _ownership_.\n"
|
||||
"* Os dados foram _movidos_ de `s1` e `s1` não está mais acessível.\n"
|
||||
"* Quando `s1` sai do escopo, nada acontece: ele não tem _ownership_.\n"
|
||||
"* Quando `s2` sai do escopo, os dados da string são liberados.\n"
|
||||
@ -5564,8 +5595,8 @@ msgid ""
|
||||
"struct Point(i32, i32);\n"
|
||||
"\n"
|
||||
"fn main() {\n"
|
||||
" let p2 = p1;\n"
|
||||
" let p1 = Point(3, 4);\n"
|
||||
" let p2 = p1;\n"
|
||||
" println!(\"p1: {p1:?}\");\n"
|
||||
" println!(\"p2: {p2:?}\");\n"
|
||||
"}\n"
|
||||
@ -6643,7 +6674,7 @@ msgstr ""
|
||||
|
||||
#: src/structs.md:1
|
||||
msgid "# Structs"
|
||||
msgstr "# Estruturas (Structs)"
|
||||
msgstr "# _Structs_ (Estruturas)"
|
||||
|
||||
#: src/structs.md:3
|
||||
msgid "Like C and C++, Rust has support for custom structs:"
|
||||
@ -6742,7 +6773,7 @@ msgstr ""
|
||||
|
||||
#: src/structs/tuple-structs.md:1
|
||||
msgid "# Tuple Structs"
|
||||
msgstr "# Estruturas Tupla (Tuple Structs)"
|
||||
msgstr "# Estruturas de Tuplas (_Tuple Structs_)"
|
||||
|
||||
#: src/structs/tuple-structs.md:3
|
||||
msgid "If the field names are unimportant, you can use a tuple struct:"
|
||||
@ -6802,7 +6833,7 @@ msgstr ""
|
||||
"struct Newtons(f64);\n"
|
||||
"\n"
|
||||
"fn calcular_forca_nas_turbinas() -> LibrasDeForca {\n"
|
||||
" todo!(“Pergunte para um cientista de foguetes da NASA”)\n"
|
||||
" todo!(\"Pergunte para um cientista de foguetes da NASA\")\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn definir_forca_nas_turbinas(force: Newtons) {\n"
|
||||
@ -6826,20 +6857,20 @@ msgid ""
|
||||
"`OddNumber(u32)`.\n"
|
||||
"* Demonstrate how to add a `f64` value to a `Newtons` type by accessing the "
|
||||
"single field in the newtype.\n"
|
||||
" * Rust generally doesn't like inexplicit things, like automatic "
|
||||
" * Rust generally doesn’t like inexplicit things, like automatic "
|
||||
"unwrapping or for instance using booleans as integers.\n"
|
||||
" * Operator overloading is discussed on Day 3 (generics).\n"
|
||||
"* The example is a subtle reference to the [Mars Climate Orbiter](https://en."
|
||||
"wikipedia.org/wiki/Mars_Climate_Orbiter) failure."
|
||||
msgstr ""
|
||||
"_Newtypes_ são uma ótima maneira de codificar informações adicionais sobre o "
|
||||
"valor em um tipo primitivo, por exemplo:\n"
|
||||
" * O número é medido em alguma unidade: `Newtons` no exemplo acima.\n"
|
||||
"* _Newtypes_ são uma ótima maneira de codificar informações adicionais sobre "
|
||||
"o valor em um tipo primitivo, por exemplo:\n"
|
||||
" * O número é medido em algumas unidades: `Newtons` no exemplo acima.\n"
|
||||
" * O valor passou por alguma validação quando foi criado, então não é "
|
||||
"preciso validá-lo novamente a cada uso: `NumeroTelefone(String)` ou "
|
||||
"`NumeroImpar(u32)`.\n"
|
||||
"* Demonstre como somar um valor `f64` em um valor do tipo `Newtons` "
|
||||
"acessando o campo único do _newtype_.\n"
|
||||
"acessando o campo único no _newtype_.\n"
|
||||
" * Geralmente, Rust não gosta de coisas implícitas, como _unwrapping_ "
|
||||
"automático ou, por exemplo, usar booleanos como inteiros.\n"
|
||||
" * Sobrecarga de operadores é discutido no Dia 3 (_generics_).\n"
|
||||
@ -6992,10 +7023,10 @@ msgstr ""
|
||||
" ```\n"
|
||||
"\n"
|
||||
"* Métodos são definidos no bloco `impl`.\n"
|
||||
"* Use struct update syntax to define a new structure using `peter`. Note "
|
||||
"that the variable `peter` will no longer be accessible afterwards.\n"
|
||||
"* Utilize `{:#?}` para imprimir _structs_ para utilizar a representação "
|
||||
"`Debug` (de Depuração)."
|
||||
"* Use a sintaxe de atualização de estruturas para definir uma nova `struct` "
|
||||
"usando `pedro`. Note que a variável `pedro` não será mais acessível após.\n"
|
||||
"* Utilize `{:#?}` para imprimir _structs_ utilizando a representação de "
|
||||
"depuração (`Debug`)."
|
||||
|
||||
#: src/enums.md:1
|
||||
msgid "# Enums"
|
||||
@ -7007,7 +7038,7 @@ msgid ""
|
||||
"different variants:"
|
||||
msgstr ""
|
||||
"A palavra-chave `enum` permite a criação de um tipo que possui algumas\n"
|
||||
"variações diferentes:"
|
||||
"variantes diferentes:"
|
||||
|
||||
#: src/enums.md:6
|
||||
msgid ""
|
||||
@ -7215,7 +7246,7 @@ msgid ""
|
||||
"Rust enums are packed tightly, taking constraints due to alignment into "
|
||||
"account:"
|
||||
msgstr ""
|
||||
"Enums, em Rust, são empacotados firmemente, levando em consideração as "
|
||||
"Enums, em Rust, são agrupados de maneira compacta, levando em consideração "
|
||||
"restrições devido ao alinhamento:"
|
||||
|
||||
#: src/enums/sizes.md:5
|
||||
@ -8277,7 +8308,7 @@ msgstr ""
|
||||
|
||||
#: src/exercises/day-2/health-statistics.md:1
|
||||
msgid "# Health Statistics"
|
||||
msgstr "# Estatísticas de saúde"
|
||||
msgstr "# Estatísticas de Saúde"
|
||||
|
||||
#: src/exercises/day-2/health-statistics.md:3
|
||||
msgid ""
|
||||
@ -8312,7 +8343,6 @@ msgstr ""
|
||||
"que estão faltando:"
|
||||
|
||||
#: src/exercises/day-2/health-statistics.md:13
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"```rust,should_panic\n"
|
||||
"// TODO: remove this when you're done with your implementation.\n"
|
||||
@ -8422,6 +8452,20 @@ msgstr ""
|
||||
" nome: String,\n"
|
||||
" idade: u32,\n"
|
||||
" peso: f32,\n"
|
||||
" num_visitas: usize,\n"
|
||||
" ult_pressao_sang: Option<(u32, u32)>,\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"pub struct Medicoes {\n"
|
||||
" altura: f32,\n"
|
||||
" pressao_sangue: (u32, u32),\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"pub struct RelatorioSaude<'a> {\n"
|
||||
" nome_paciente: &'a str,\n"
|
||||
" num_visitas: u32,\n"
|
||||
" dif_altura: f32,\n"
|
||||
" dif_pressao_sangue: Option<(i32, i32)>,\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"impl Usuario {\n"
|
||||
@ -8437,7 +8481,11 @@ msgstr ""
|
||||
" unimplemented!()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" pub fn peso(&self) -> f32 {\n"
|
||||
" pub fn altura(&self) -> f32 {\n"
|
||||
" unimplemented!()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" pub fn visitas_medico(&self) -> u32 {\n"
|
||||
" unimplemented!()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
@ -8445,7 +8493,7 @@ msgstr ""
|
||||
" unimplemented!()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" pub fn definir_peso(&mut self, novo_peso: f32) {\n"
|
||||
" pub fn definir_altura(&mut self, novo_altura: f32) {\n"
|
||||
" unimplemented!()\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
@ -8456,13 +8504,13 @@ msgstr ""
|
||||
"}\n"
|
||||
"\n"
|
||||
"#[test]\n"
|
||||
"fn test_peso() {\n"
|
||||
"fn test_altura() {\n"
|
||||
" let beto = Usuario::new(String::from(\"Beto\"), 32, 155.2);\n"
|
||||
" assert_eq!(beto.peso(), 155.2);\n"
|
||||
" assert_eq!(beto.altura(), 155.2);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"#[test]\n"
|
||||
"fn test_set_age() {\n"
|
||||
"fn test_definir_idade() {\n"
|
||||
" let mut beto = Usuario::new(String::from(\"Beto\"), 32, 155.2);\n"
|
||||
" assert_eq!(beto.idade(), 32);\n"
|
||||
" beto.definir_idade(33);\n"
|
||||
@ -8472,7 +8520,7 @@ msgstr ""
|
||||
|
||||
#: src/exercises/day-2/points-polygons.md:1
|
||||
msgid "# Polygon Struct"
|
||||
msgstr "# Estrutura para polígono"
|
||||
msgstr "# _Struct_ para Polígono"
|
||||
|
||||
#: src/exercises/day-2/points-polygons.md:3
|
||||
msgid ""
|
||||
@ -8482,7 +8530,7 @@ msgid ""
|
||||
"the\n"
|
||||
"tests pass:"
|
||||
msgstr ""
|
||||
"Vamos criar uma estrutura `Poligono` que contém alguns `Pontos`. Copie o "
|
||||
"Vamos criar um _struct_ `Poligono` que contém alguns `Pontos`. Copie o "
|
||||
"código abaixo\n"
|
||||
"em <https://play.rust-lang.org/> e preencha os métodos que faltam para fazer "
|
||||
"os\n"
|
||||
@ -10701,7 +10749,7 @@ msgid ""
|
||||
"\n"
|
||||
" ```rust,ignore\n"
|
||||
" #[path = \"some/path.rs\"]\n"
|
||||
" mod some_module { }\n"
|
||||
" mod some_module;\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" This is useful, for example, if you would like to place tests for a module "
|
||||
@ -11065,7 +11113,6 @@ msgid ""
|
||||
msgstr ""
|
||||
"Rust oferece suporte a tipos genéricos, que permitem algoritmos ou "
|
||||
"estruturas de dados\n"
|
||||
|
||||
" (como ordenação ou árvore binária)\n"
|
||||
"abstrair os tipos de dados usados ou armazenados."
|
||||
|
||||
@ -11515,7 +11562,6 @@ msgstr ""
|
||||
" '- - - - - - - - - - - - - - - - - - - - - "
|
||||
"- - -'\n"
|
||||
"\n"
|
||||
|
||||
"```"
|
||||
|
||||
#: src/traits/trait-objects.md:72
|
||||
@ -17085,7 +17131,7 @@ msgid ""
|
||||
"exist. Once a pin is\n"
|
||||
" moved out of the port struct nobody else can take it.\n"
|
||||
" * Changing the configuration of a pin consumes the old pin instance, so you "
|
||||
"can't keep use the old\n"
|
||||
"can’t keep use the old\n"
|
||||
" instance afterwards.\n"
|
||||
" * The type of a value indicates the state that it is in: e.g. in this case, "
|
||||
"the configuration state\n"
|
||||
@ -18152,9 +18198,9 @@ msgid ""
|
||||
" writeln!(uart, \"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\").unwrap();\n"
|
||||
"\n"
|
||||
" loop {\n"
|
||||
" if let Some(b) = uart.read_byte() {\n"
|
||||
" uart.write_byte(b);\n"
|
||||
" match b {\n"
|
||||
" if let Some(byte) = uart.read_byte() {\n"
|
||||
" uart.write_byte(byte);\n"
|
||||
" match byte {\n"
|
||||
" b'\\r' => {\n"
|
||||
" uart.write_byte(b'\\n');\n"
|
||||
" }\n"
|
||||
@ -21024,8 +21070,7 @@ msgstr "Seu arquivo `src/main.rs` deve se parecer com isto:"
|
||||
#: src/exercises/concurrency/link-checker.md:57
|
||||
msgid ""
|
||||
"```rust,compile_fail\n"
|
||||
"use reqwest::blocking::{get, Response};\n"
|
||||
"use reqwest::Url;\n"
|
||||
"use reqwest::{blocking::Client, Url};\n"
|
||||
"use scraper::{Html, Selector};\n"
|
||||
"use thiserror::Error;\n"
|
||||
"\n"
|
||||
@ -21033,34 +21078,57 @@ msgid ""
|
||||
"enum Error {\n"
|
||||
" #[error(\"request error: {0}\")]\n"
|
||||
" ReqwestError(#[from] reqwest::Error),\n"
|
||||
" #[error(\"bad http response: {0}\")]\n"
|
||||
" BadResponse(String),\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn extract_links(response: Response) -> Result<Vec<Url>, Error> {\n"
|
||||
" let base_url = response.url().to_owned();\n"
|
||||
" let document = response.text()?;\n"
|
||||
" let html = Html::parse_document(&document);\n"
|
||||
" let selector = Selector::parse(\"a\").unwrap();\n"
|
||||
"#[derive(Debug)]\n"
|
||||
"struct CrawlCommand {\n"
|
||||
" url: Url,\n"
|
||||
" extract_links: bool,\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
" let mut valid_urls = Vec::new();\n"
|
||||
" for element in html.select(&selector) {\n"
|
||||
" if let Some(href) = element.value().attr(\"href\") {\n"
|
||||
" match base_url.join(href) {\n"
|
||||
" Ok(url) => valid_urls.push(url),\n"
|
||||
" Err(err) => {\n"
|
||||
" println!(\"On {base_url}: could not parse {href:?}: "
|
||||
"{err} (ignored)\",);\n"
|
||||
" }\n"
|
||||
"fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, "
|
||||
"Error> {\n"
|
||||
" println!(\"Checking {:#}\", command.url);\n"
|
||||
" let response = client.get(command.url.clone()).send()?;\n"
|
||||
" if !response.status().is_success() {\n"
|
||||
" return Err(Error::BadResponse(response.status().to_string()));\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" let mut link_urls = Vec::new();\n"
|
||||
" if !command.extract_links {\n"
|
||||
" return Ok(link_urls);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" let base_url = response.url().to_owned();\n"
|
||||
" let body_text = response.text()?;\n"
|
||||
" let document = Html::parse_document(&body_text);\n"
|
||||
"\n"
|
||||
" let selector = Selector::parse(\"a\").unwrap();\n"
|
||||
" let href_values = document\n"
|
||||
" .select(&selector)\n"
|
||||
" .filter_map(|element| element.value().attr(\"href\"));\n"
|
||||
" for href in href_values {\n"
|
||||
" match base_url.join(href) {\n"
|
||||
" Ok(link_url) => {\n"
|
||||
" link_urls.push(link_url);\n"
|
||||
" }\n"
|
||||
" Err(err) => {\n"
|
||||
" println!(\"On {base_url:#}: ignored unparsable {href:?}: "
|
||||
"{err}\");\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" Ok(valid_urls)\n"
|
||||
" Ok(link_urls)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn main() {\n"
|
||||
" let client = Client::new();\n"
|
||||
" let start_url = Url::parse(\"https://www.google.org\").unwrap();\n"
|
||||
" let response = get(start_url).unwrap();\n"
|
||||
" match extract_links(response) {\n"
|
||||
" let crawl_command = CrawlCommand{ url: start_url, extract_links: "
|
||||
"true };\n"
|
||||
" match visit_page(&client, &crawl_command) {\n"
|
||||
" Ok(links) => println!(\"Links: {links:#?}\"),\n"
|
||||
" Err(err) => println!(\"Could not extract links: {err:#}\"),\n"
|
||||
" }\n"
|
||||
@ -21068,11 +21136,11 @@ msgid ""
|
||||
"```"
|
||||
msgstr ""
|
||||
|
||||
#: src/exercises/concurrency/link-checker.md:100
|
||||
#: src/exercises/concurrency/link-checker.md:120
|
||||
msgid "Run the code in `src/main.rs` with"
|
||||
msgstr "Execute o código em `src/main.rs` com"
|
||||
|
||||
#: src/exercises/concurrency/link-checker.md:102
|
||||
#: src/exercises/concurrency/link-checker.md:122
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"```shell\n"
|
||||
@ -21083,12 +21151,12 @@ msgstr ""
|
||||
"$ cargo run\n"
|
||||
"```"
|
||||
|
||||
#: src/exercises/concurrency/link-checker.md:106
|
||||
#: src/exercises/concurrency/link-checker.md:126
|
||||
#: src/exercises/concurrency/chat-app.md:140
|
||||
msgid "## Tasks"
|
||||
msgstr "## Tarefas"
|
||||
|
||||
#: src/exercises/concurrency/link-checker.md:108
|
||||
#: src/exercises/concurrency/link-checker.md:128
|
||||
msgid ""
|
||||
"* Use threads to check the links in parallel: send the URLs to be checked to "
|
||||
"a\n"
|
||||
@ -22847,7 +22915,7 @@ msgstr "# Dia 1 Exercícios matinais"
|
||||
|
||||
#: src/exercises/day-1/solutions-morning.md:3
|
||||
msgid "## Arrays and `for` Loops"
|
||||
msgstr "## Vetores e laços `for`"
|
||||
msgstr "## Matrizes e Loops `for`"
|
||||
|
||||
#: src/exercises/day-1/solutions-morning.md:5
|
||||
msgid "([back to exercise](for-loops.md))"
|
||||
@ -24668,6 +24736,211 @@ msgid ""
|
||||
"```"
|
||||
msgstr ""
|
||||
|
||||
#: src/exercises/concurrency/solutions-morning.md:104
|
||||
#, fuzzy
|
||||
msgid "## Link Checker"
|
||||
msgstr "# Verificador de links _multi-threads_"
|
||||
|
||||
#: src/exercises/concurrency/solutions-morning.md:106
|
||||
#, fuzzy
|
||||
msgid "([back to exercise](link-checker.md))"
|
||||
msgstr "([voltar ao exercício](luhn.md))"
|
||||
|
||||
#: src/exercises/concurrency/solutions-morning.md:108
|
||||
msgid ""
|
||||
"```rust,compile_fail\n"
|
||||
"// Copyright 2022 Google LLC\n"
|
||||
"//\n"
|
||||
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
|
||||
"// you may not use this file except in compliance with the License.\n"
|
||||
"// You may obtain a copy of the License at\n"
|
||||
"//\n"
|
||||
"// http://www.apache.org/licenses/LICENSE-2.0\n"
|
||||
"//\n"
|
||||
"// Unless required by applicable law or agreed to in writing, software\n"
|
||||
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
|
||||
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
|
||||
"// See the License for the specific language governing permissions and\n"
|
||||
"// limitations under the License.\n"
|
||||
"\n"
|
||||
"use std::{sync::Arc, sync::Mutex, sync::mpsc, thread};\n"
|
||||
"\n"
|
||||
"// ANCHOR: setup\n"
|
||||
"use reqwest::{blocking::Client, Url};\n"
|
||||
"use scraper::{Html, Selector};\n"
|
||||
"use thiserror::Error;\n"
|
||||
"\n"
|
||||
"#[derive(Error, Debug)]\n"
|
||||
"enum Error {\n"
|
||||
" #[error(\"request error: {0}\")]\n"
|
||||
" ReqwestError(#[from] reqwest::Error),\n"
|
||||
" #[error(\"bad http response: {0}\")]\n"
|
||||
" BadResponse(String),\n"
|
||||
"}\n"
|
||||
"// ANCHOR_END: setup\n"
|
||||
"\n"
|
||||
"// ANCHOR: visit_page\n"
|
||||
"#[derive(Debug)]\n"
|
||||
"struct CrawlCommand {\n"
|
||||
" url: Url,\n"
|
||||
" extract_links: bool,\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, "
|
||||
"Error> {\n"
|
||||
" println!(\"Checking {:#}\", command.url);\n"
|
||||
" let response = client.get(command.url.clone()).send()?;\n"
|
||||
" if !response.status().is_success() {\n"
|
||||
" return Err(Error::BadResponse(response.status().to_string()));\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" let mut link_urls = Vec::new();\n"
|
||||
" if !command.extract_links {\n"
|
||||
" return Ok(link_urls);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" let base_url = response.url().to_owned();\n"
|
||||
" let body_text = response.text()?;\n"
|
||||
" let document = Html::parse_document(&body_text);\n"
|
||||
"\n"
|
||||
" let selector = Selector::parse(\"a\").unwrap();\n"
|
||||
" let href_values = document\n"
|
||||
" .select(&selector)\n"
|
||||
" .filter_map(|element| element.value().attr(\"href\"));\n"
|
||||
" for href in href_values {\n"
|
||||
" match base_url.join(href) {\n"
|
||||
" Ok(link_url) => {\n"
|
||||
" link_urls.push(link_url);\n"
|
||||
" }\n"
|
||||
" Err(err) => {\n"
|
||||
" println!(\"On {base_url:#}: ignored unparsable {href:?}: "
|
||||
"{err}\");\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" Ok(link_urls)\n"
|
||||
"}\n"
|
||||
"// ANCHOR_END: visit_page\n"
|
||||
"\n"
|
||||
"struct CrawlState {\n"
|
||||
" domain: String,\n"
|
||||
" visited_pages: std::collections::HashSet<String>,\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"impl CrawlState {\n"
|
||||
" fn new(start_url: &Url) -> CrawlState {\n"
|
||||
" let mut visited_pages = std::collections::HashSet::new();\n"
|
||||
" visited_pages.insert(start_url.as_str().to_string());\n"
|
||||
" CrawlState {\n"
|
||||
" domain: start_url.domain().unwrap().to_string(),\n"
|
||||
" visited_pages,\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" /// Determine whether links within the given page should be extracted.\n"
|
||||
" fn should_extract_links(&self, url: &Url) -> bool {\n"
|
||||
" let Some(url_domain) = url.domain() else {\n"
|
||||
" return false;\n"
|
||||
" };\n"
|
||||
" url_domain == self.domain\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" /// Mark the given page as visited, returning true if it had already\n"
|
||||
" /// been visited.\n"
|
||||
" fn mark_visited(&mut self, url: &Url) -> bool {\n"
|
||||
" self.visited_pages.insert(url.as_str().to_string())\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"type CrawlResult = Result<Vec<Url>, (Url, Error)>;\n"
|
||||
"fn spawn_crawler_threads(\n"
|
||||
" command_receiver: mpsc::Receiver<CrawlCommand>,\n"
|
||||
" result_sender: mpsc::Sender<CrawlResult>,\n"
|
||||
" thread_count: u32,\n"
|
||||
") {\n"
|
||||
" let command_receiver = Arc::new(Mutex::new(command_receiver));\n"
|
||||
"\n"
|
||||
" for _ in 0..thread_count {\n"
|
||||
" let result_sender = result_sender.clone();\n"
|
||||
" let command_receiver = command_receiver.clone();\n"
|
||||
" thread::spawn(move || {\n"
|
||||
" let client = Client::new();\n"
|
||||
" loop {\n"
|
||||
" let command_result = {\n"
|
||||
" let receiver_guard = command_receiver.lock().unwrap();\n"
|
||||
" receiver_guard.recv()\n"
|
||||
" };\n"
|
||||
" let Ok(crawl_command) = command_result else {\n"
|
||||
" // The sender got dropped. No more commands coming in.\n"
|
||||
" break;\n"
|
||||
" };\n"
|
||||
" let crawl_result = match visit_page(&client, &crawl_command) "
|
||||
"{\n"
|
||||
" Ok(link_urls) => Ok(link_urls),\n"
|
||||
" Err(error) => Err((crawl_command.url, error)),\n"
|
||||
" };\n"
|
||||
" result_sender.send(crawl_result).unwrap();\n"
|
||||
" }\n"
|
||||
" });\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn control_crawl(\n"
|
||||
" start_url: Url,\n"
|
||||
" command_sender: mpsc::Sender<CrawlCommand>,\n"
|
||||
" result_receiver: mpsc::Receiver<CrawlResult>,\n"
|
||||
") -> Vec<Url> {\n"
|
||||
" let mut crawl_state = CrawlState::new(&start_url);\n"
|
||||
" let start_command = CrawlCommand { url: start_url, extract_links: "
|
||||
"true };\n"
|
||||
" command_sender.send(start_command).unwrap();\n"
|
||||
" let mut pending_urls = 1;\n"
|
||||
"\n"
|
||||
" let mut bad_urls = Vec::new();\n"
|
||||
" while pending_urls > 0 {\n"
|
||||
" let crawl_result = result_receiver.recv().unwrap();\n"
|
||||
" pending_urls -= 1;\n"
|
||||
"\n"
|
||||
" match crawl_result {\n"
|
||||
" Ok(link_urls) => {\n"
|
||||
" for url in link_urls {\n"
|
||||
" if crawl_state.mark_visited(&url) {\n"
|
||||
" let extract_links = crawl_state."
|
||||
"should_extract_links(&url);\n"
|
||||
" let crawl_command = CrawlCommand { url, "
|
||||
"extract_links };\n"
|
||||
" command_sender.send(crawl_command).unwrap();\n"
|
||||
" pending_urls += 1;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" Err((url, error)) => {\n"
|
||||
" bad_urls.push(url);\n"
|
||||
" println!(\"Got crawling error: {:#}\", error);\n"
|
||||
" continue;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" bad_urls\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn check_links(start_url: Url) -> Vec<Url> {\n"
|
||||
" let (result_sender, result_receiver) = mpsc::channel::<CrawlResult>();\n"
|
||||
" let (command_sender, command_receiver) = mpsc::channel::"
|
||||
"<CrawlCommand>();\n"
|
||||
" spawn_crawler_threads(command_receiver, result_sender, 16);\n"
|
||||
" control_crawl(start_url, command_sender, result_receiver)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fn main() {\n"
|
||||
" let start_url = reqwest::Url::parse(\"https://www.google.org\")."
|
||||
"unwrap();\n"
|
||||
" let bad_urls = check_links(start_url);\n"
|
||||
" println!(\"Bad URLs: {:#?}\", bad_urls);\n"
|
||||
"}\n"
|
||||
"```"
|
||||
msgstr ""
|
||||
|
||||
#: src/exercises/concurrency/solutions-afternoon.md:1
|
||||
#, fuzzy
|
||||
msgid "# Concurrency Afternoon Exercise"
|
||||
|
Loading…
Reference in New Issue
Block a user