diff --git a/ro-RO/assets/CNAME b/ro-RO/assets/CNAME new file mode 100644 index 000000000..c6cd02a9d --- /dev/null +++ b/ro-RO/assets/CNAME @@ -0,0 +1 @@ +practice.rs \ No newline at end of file diff --git a/ro-RO/assets/custom3.js b/ro-RO/assets/custom3.js new file mode 100644 index 000000000..3f70daa4e --- /dev/null +++ b/ro-RO/assets/custom3.js @@ -0,0 +1,156 @@ +var initAll = function () { + var path = window.location.pathname; + if (path.endsWith("/print.html")) { + return; + } + + var images = document.querySelectorAll("main img") + Array.prototype.forEach.call(images, function (img) { + img.addEventListener("click", function () { + BigPicture({ + el: img, + }); + }); + }); + + // Un-active everything when you click it + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { + el.addEventHandler("click", function () { + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { + el.classList.remove("active"); + }); + el.classList.add("active"); + }); + }); + + var updateFunction = function () { + var id = null; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function (el) { + if (window.pageYOffset >= el.offsetTop) { + id = el; + } + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { + el.classList.remove("active"); + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function (el) { + if (id == null) { + return; + } + if (id.href.localeCompare(el.href) == 0) { + el.classList.add("active"); + } + }); + }; + + var pagetoc = document.getElementsByClassName("pagetoc")[0]; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function (el) { + var link = document.createElement("a"); + + // Indent shows hierarchy + var indent = ""; + switch (el.parentElement.tagName) { + case "H1": + return; + case "H3": + indent = "20px"; + break; + case "H4": + indent = "40px"; + break; + default: + break; + } + + link.appendChild(document.createTextNode(el.text)); + link.style.paddingLeft = indent; + link.href = el.href; + pagetoc.appendChild(link); + }); + updateFunction.call(); + + // Handle active elements on scroll + window.addEventListener("scroll", updateFunction); + + document.getElementById("theme-list").addEventListener("click", function (e) { + var iframe = document.querySelector('.giscus-frame'); + if (!iframe) return; + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else { + return; + } + + // 若当前 mdbook 主题不是 Light 或 Rust ,则将 giscuz 主题设置为 transparent_dark + var giscusTheme = "light" + if (theme != "light" && theme != "rust") { + giscusTheme = "transparent_dark"; + } + + var msg = { + setConfig: { + theme: giscusTheme + } + }; + iframe.contentWindow.postMessage({ giscus: msg }, 'https://giscus.app'); + }); + + pagePath = pagePath.replace("index.md", ""); + pagePath = pagePath.replace(".md", ""); + if (pagePath.length > 0) { + if (pagePath.charAt(pagePath.length-1) == "/"){ + pagePath = pagePath.substring(0, pagePath.length-1) + } + }else { + pagePath = "index" + } + + // add visitors count + var ele = document.createElement("div"); + ele.setAttribute("align","center"); + var count = document.createElement("img") + // count.setAttribute("src", "https://visitor-badge.glitch.me/badge?page_id=practice/en/" + path); + count.setAttribute("src", "https://api.visitorbadge.io/api/visitors?labelColor=%23595959&countColor=%230d81c3&style=flat-square&path=practice/en/" + path); + ele.appendChild(count); + var divider =document.createElement("hr") + + document.getElementById("giscus-container").appendChild(ele); + document.getElementById("giscus-container").appendChild(divider); + + // 选取浏览器默认使用的语言 + const lang = navigator.language || navigator.userLanguage + + // 若当前 mdbook 主题为 Light 或 Rust ,则将 giscuz 主题设置为 light + var theme = "transparent_dark"; + const themeClass = document.getElementsByTagName("html")[0].className; + if (themeClass.indexOf("light") != -1 || themeClass.indexOf("rust") != -1) { + theme = "light" + } + + var script = document.createElement("script") + script.type = "text/javascript"; + script.src = "https://giscus.app/client.js"; + script.async = true; + script.crossOrigin = "anonymous"; + script.setAttribute("data-repo", "sunface/rust-by-practice"); + script.setAttribute("data-repo-id", "MDEwOlJlcG9zaXRvcnkxMjk5OTAzOTY="); + script.setAttribute("data-category", "Book Comments"); + script.setAttribute("data-category-id", "DIC_kwDOB79-_M4COQmx"); + script.setAttribute("data-mapping", "specific"); + script.setAttribute("data-term", pagePath); + script.setAttribute("data-reactions-enabled", "1"); + script.setAttribute("data-emit-metadata", "0"); + script.setAttribute("data-input-position", "top"); + script.setAttribute("data-theme", theme); + script.setAttribute("data-lang", lang == 'en-US' ? 'en' : lang); + // 预先加载评论会更好,这样用户读到那边时,评论就加载好了 + // script.setAttribute("data-loading", "lazy"); + document.getElementById("giscus-container").appendChild(script); +}; + +window.addEventListener('load', initAll); \ No newline at end of file diff --git a/ro-RO/assets/header.jpg b/ro-RO/assets/header.jpg new file mode 100644 index 000000000..7a18c7a45 Binary files /dev/null and b/ro-RO/assets/header.jpg differ diff --git a/ro-RO/assets/header1.png b/ro-RO/assets/header1.png new file mode 100644 index 000000000..259779c32 Binary files /dev/null and b/ro-RO/assets/header1.png differ diff --git a/ro-RO/assets/lang.js b/ro-RO/assets/lang.js new file mode 100644 index 000000000..061d37586 --- /dev/null +++ b/ro-RO/assets/lang.js @@ -0,0 +1,26 @@ +(function () { + var path = window.location.pathname; + var link = "https://practice.rs" + path; + var word = "English"; + var lang = "zh-CN"; + var changeLang = "切换到英语"; + + if (window.location.href.indexOf("zh.") == -1) { + link = "https://zh.practice.rs" + path; + word = "简体中文"; + lang = "en"; + changeLang = "Switch to Chinese" + } + + var lang_node = ''; + if (link != '') { + lang_node = ' ' + word + ''; + } + + console.log(lang_node) + var insertNode = document.getElementsByClassName('right-buttons'); + if (insertNode.length > 0) { + var html = insertNode[0].innerHTML; + insertNode[0].innerHTML = html + lang_node; + } + })() \ No newline at end of file diff --git a/ro-RO/assets/logo.png b/ro-RO/assets/logo.png new file mode 100644 index 000000000..bb2ac3ca3 Binary files /dev/null and b/ro-RO/assets/logo.png differ diff --git a/ro-RO/assets/temp.md b/ro-RO/assets/temp.md new file mode 100644 index 000000000..090250fba --- /dev/null +++ b/ro-RO/assets/temp.md @@ -0,0 +1,87 @@ +# 字符、布尔、单元类型 + +### 字符 +🌟 +```rust + +use std::mem::size_of_val; +fn main() { + let c1 = 'a'; + assert_eq!(size_of_val(&c1),1); + + let c2 = '中'; + assert_eq!(size_of_val(&c2),3); +} +``` + +🌟 +```rust + +fn main() { + let c1 = "中"; + print_char(c1); +} + +fn print_char(c : char) { + println!("{}", c); +} +``` + +### 布尔 +🌟 +```rust + +// 让 println! 工作 +fn main() { + let _f: bool = false; + + let t = true; + if !t { + println!("hello, world"); + } +} +``` + +🌟 +```rust + +fn main() { + let f = true; + let t = true && false; + assert_eq!(t, f); +} +``` + + +### 单元类型 +🌟🌟 +```rust + +// 让代码工作,但不要修改 `implicitly_ret_unit` ! +fn main() { + let _v: () = (); + + let v = (2, 3); + assert_eq!(v, implicitly_ret_unit()) +} + +fn implicitly_ret_unit() { + println!("I will returen a ()") +} + +// 不要使用下面的函数,它只用于演示! +fn explicitly_ret_unit() -> () { + println!("I will returen a ()") +} +``` + +🌟🌟 单元类型占用的内存大小是多少? +```rust + +// 让代码工作:修改 `assert!` 中的 `4` +use std::mem::size_of_val; +fn main() { + let unit: () = (); + assert!(size_of_val(&unit) == 4); +} +``` \ No newline at end of file diff --git a/ro-RO/book.toml b/ro-RO/book.toml new file mode 100644 index 000000000..98fe5ccaa --- /dev/null +++ b/ro-RO/book.toml @@ -0,0 +1,22 @@ +[book] +title = "Rust prin practică" +description = "Learn Rust with Example, Exercise and real Practice, written with ❤️ by https://course.rs team" +authors = ["sunface, https://im.dev"] +language = "en" + +[output.html.playpen] +editable = true +editor = "ace" + +[output.html.fold] +enable = true +level = 1 + +[output.html] +additional-css = ["theme/style1.css"] +additional-js = ["assets/custom3.js","assets/lang.js"] +git-repository-url = "https://github.com/sunface/rust-by-practice" +edit-url-template = "https://github.com/sunface/rust-by-practice/edit/master/ro-RO/{path}" + +[rust] +edition = "2021" \ No newline at end of file diff --git a/ro-RO/deploy.sh b/ro-RO/deploy.sh new file mode 100644 index 000000000..880ab5cef --- /dev/null +++ b/ro-RO/deploy.sh @@ -0,0 +1,23 @@ +## this script deploys the static website of course.rs to github pages + +## build static website for book +mdbook build +## copy CNAME info to book dir +cp ./assets/CNAME ./book/ + +## init git repo +cd book +git init +git config user.name "sunface" +git config user.email "cto@188.com" +git add . +git commit -m 'deploy' +git branch -M gh-pages +git remote add origin https://github.com/sunface/rust-by-practice + +## push to github pages +git push -u -f origin gh-pages + +## deploy zh-CN +cd ../../zh-CN +./deploy \ No newline at end of file diff --git a/ro-RO/src/.gitignore b/ro-RO/src/.gitignore new file mode 100644 index 000000000..e9c072897 --- /dev/null +++ b/ro-RO/src/.gitignore @@ -0,0 +1 @@ +book \ No newline at end of file diff --git a/ro-RO/src/SUMMARY.md b/ro-RO/src/SUMMARY.md new file mode 100644 index 000000000..14bf0d894 --- /dev/null +++ b/ro-RO/src/SUMMARY.md @@ -0,0 +1,94 @@ +# Summary + +- [Rust By Practice](why-exercise.md) +- [Small projects with Elegant code](elegant-code-base.md) +- [Variables](variables.md) +- [Basic Types](basic-types/intro.md) + - [Numbers](basic-types/numbers.md) + - [Char, Bool and Unit](basic-types/char-bool-unit.md) + - [Statements and Expressions](basic-types/statements-expressions.md) + - [Functions](basic-types/functions.md) +- [Ownership and Borrowing](ownership/intro.md) + - [Ownership](ownership/ownership.md) + - [Reference and Borrowing](ownership/borrowing.md) +- [Compound Types](compound-types/intro.md) + - [string](compound-types/string.md) + - [Array](compound-types/array.md) + - [Slice](compound-types/slice.md) + - [Tuple](compound-types/tuple.md) + - [Struct](compound-types/struct.md) + - [Enum](compound-types/enum.md) +- [Flow Control](flow-control.md) +- [Pattern Match](pattern-match/intro.md) + - [match, matches! and if let](pattern-match/match-iflet.md) + - [Patterns](pattern-match/patterns.md) +- [Method & Associated function](method.md) +- [Generics and Traits](generics-traits/intro.md) + - [Generics](generics-traits/generics.md) + - [Const Generics](generics-traits/const-generics.md) + - [Traits](generics-traits/traits.md) + - [Trait Object](generics-traits/trait-object.md) + - [Advanced Traits](generics-traits/advanced-traits.md) +- [Collection Types](collections/intro.md) + - [String](collections/string.md) + - [Vector](collections/vector.md) + - [HashMap](collections/hashmap.md) +- [Type Conversion](type-conversions/intro.md) + - [as](type-conversions/as.md) + - [From/Into](type-conversions/from-into.md) + - [Others](type-conversions/others.md) +- [Result and panic](result-panic/intro.md) + - [panic!](result-panic/panic.md) + - [Result and ?](result-panic/result.md) +- [Crate and Module](crate-module/intro.md) + - [Package and Crate](crate-module/crate.md) + - [Module](crate-module/module.md) + - [Advanced use and pub](crate-module/use-pub.md) +- [Comments and Docs](comments-docs.md) +- [Formatted output](formatted-output/intro.md) + - [println! and format!](formatted-output/println.md) + - [Debug and Display](formatted-output/debug-display.md) + - [formating](formatted-output/formatting.md) +- [Lifetime](lifetime/intro.md) + - [basic](lifetime/basic.md) + - [&'static and T: 'static](lifetime/static.md) + - [advanced](lifetime/advance.md) +- [Functional programing](functional-programing/intro.md) + - [Closure](functional-programing/closure.md) + - [Iterator](functional-programing/iterator.md) +- [newtype and DST](newtype-sized.md) +- [Smart pointers TODO](smart-pointers/intro.md) + - [Box](smart-pointers/box.md) + - [Deref](smart-pointers/deref.md) + - [Drop](smart-pointers/drop.md) + - [Rc and Arc](smart-pointers/rc-arc.md) + - [Cell and RefCell](smart-pointers/cell-refcell.md) +- [Weak and Circle reference TODO](weak.md) +- [Self referential TODO](self-referential.md) +- [Threads TODO](threads/intro.md) + - [Basic using](threads/basic-using.md) + - [Message passing](threads/message-passing.md) + - [Sync](threads/sync.md) + - [Atomic](threads/atomic.md) + - [Send and Sync](threads/send-sync.md) +- [Global variables TODO](global-variables.md) +- [Errors TODO](errors.md) +- [Unsafe doing](unsafe/intro.md) + - [Inline assembly](unsafe/inline-asm.md) +- [Macro TODO](macro.md) +- [Tests TODO](tests/intro.md) + - [Write Tests](tests/write-tests.md) + - [Benchmark](tests/benchmark.md) + - [Unit and Integration](tests/unit-integration.md) + - [Assertions](tests/assertions.md) +- [Async/Await TODO](async/intro.md) + - [async and await!](async/async-await.md) + - [Future](async/future.md) + - [Pin and Unpin](async/pin-unpin.md) + - [Stream](async/stream.md) + +- [Standard Library TODO](std/intro.md) + - [String](std/String.md) + +- [Fighting with Compiler](fight-compiler/intro.md) + - [Borrowing](fight-compiler/borrowing.md) \ No newline at end of file diff --git a/ro-RO/src/about.md b/ro-RO/src/about.md new file mode 100644 index 000000000..65054b7d8 --- /dev/null +++ b/ro-RO/src/about.md @@ -0,0 +1 @@ +# Rust By Practice diff --git a/ro-RO/src/async/async-await.md b/ro-RO/src/async/async-await.md new file mode 100644 index 000000000..a20c0b854 --- /dev/null +++ b/ro-RO/src/async/async-await.md @@ -0,0 +1 @@ +# async and await! diff --git a/ro-RO/src/async/future.md b/ro-RO/src/async/future.md new file mode 100644 index 000000000..5f24b0e0a --- /dev/null +++ b/ro-RO/src/async/future.md @@ -0,0 +1 @@ +# Future diff --git a/ro-RO/src/async/intro.md b/ro-RO/src/async/intro.md new file mode 100644 index 000000000..70bdb9f49 --- /dev/null +++ b/ro-RO/src/async/intro.md @@ -0,0 +1 @@ +# Async/Await diff --git a/ro-RO/src/async/pin-unpin.md b/ro-RO/src/async/pin-unpin.md new file mode 100644 index 000000000..8655bd18d --- /dev/null +++ b/ro-RO/src/async/pin-unpin.md @@ -0,0 +1 @@ +# Pin and Unpin diff --git a/ro-RO/src/async/stream.md b/ro-RO/src/async/stream.md new file mode 100644 index 000000000..867bd88c3 --- /dev/null +++ b/ro-RO/src/async/stream.md @@ -0,0 +1 @@ +# Stream diff --git a/ro-RO/src/basic-types/char-bool-unit.md b/ro-RO/src/basic-types/char-bool-unit.md new file mode 100644 index 000000000..1192fb7b7 --- /dev/null +++ b/ro-RO/src/basic-types/char-bool-unit.md @@ -0,0 +1,100 @@ +# Char, Bool and Unit + +### Char +1. 🌟 +```rust,editable + +// Faceți să funcționeze +use std::mem::size_of_val; +fn main() { + let c1 = 'a'; + assert_eq!(size_of_val(&c1),1); + + let c2 = '中'; + assert_eq!(size_of_val(&c2),3); + + println!("Success!"); +} +``` + +2. 🌟 +```rust,editable + +// Faceți să funcționeze +fn main() { + let c1 = "中"; + print_char(c1); +} + +fn print_char(c : char) { + println!("{}", c); +} +``` + +### Bool +3. 🌟 +```rust,editable + +// Faceți println! să funcționeze +fn main() { + let _f: bool = false; + + let t = true; + if !t { + println!("Success!"); + } +} +``` + +4. 🌟 +```rust,editable + +// Faceți să funcționeze +fn main() { + let f = true; + let t = true && false; + assert_eq!(t, f); + + println!("Success!"); +} +``` + + +### Unit type +5. 🌟🌟 +```rust,editable + +// Faceți să funcționeze fără a modifica `implicitly_ret_unit` ! +fn main() { + let _v: () = (); + + let v = (2, 3); + assert_eq!(v, implicitly_ret_unit()); + + println!("Success!"); +} + +fn implicitly_ret_unit() { + println!("I will return a ()"); +} + +// Nu folosiți asta +fn explicitly_ret_unit() -> () { + println!("I will return a ()"); +} +``` + +6. 🌟🌟 What's the size of the unit type? +```rust,editable + +// Modificați `4` in 'assert' pentru a face să funcționeze +use std::mem::size_of_val; +fn main() { + let unit: () = (); + assert!(size_of_val(&unit) == 4); + + println!("Success!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice)(sub calea soluțiilor), dar utilizați-le doar atunci când aveți nevoie. diff --git a/ro-RO/src/basic-types/functions.md b/ro-RO/src/basic-types/functions.md new file mode 100644 index 000000000..5b7aa8174 --- /dev/null +++ b/ro-RO/src/basic-types/functions.md @@ -0,0 +1,101 @@ +# Functions +1. 🌟🌟🌟 +```rust,editable + +fn main() { + // Nu modificați următoarele două linii! + let (x, y) = (1, 2); + let s = sum(x, y); + + assert_eq!(s, 3); + + println!("Success!"); +} + +fn sum(x, y: i32) { + x + y; +} +``` + + +2. 🌟 +```rust,editable +fn main() { + print(); +} + +// Inlocuiți i32 cu un alt tip de date +fn print() -> i32 { + println!("Success!"); +} +``` + + +3. 🌟🌟🌟 + +```rust,editable +// Rezolvați in două moduri +// NU lăsați `println!` să ruleze +fn main() { + never_return(); + + println!("Failed!"); +} + +fn never_return() -> ! { + // Implementați această funcție, nu modificați semnăturile funcției + +} +``` + +### Diverging functions +Funcțiile divergente nu se întorc niciodată la apelant, astfel că pot fi folosite în locuri unde se așteaptă o valoare de orice tip. + +4. 🌟🌟 +```rust,editable + +fn main() { + println!("Success!"); +} + +fn get_option(tp: u8) -> Option { + match tp { + 1 => { + // TODO + } + _ => { + // TODO + } + }; + + // În loc să returnăm un "None", folosim în schimb o funcție divergentă. + never_return_fn() +} + +// IMPLMENTAȚI această funcție în TREI moduri +fn never_return_fn() -> ! { + +} +``` + +5. 🌟🌟 +```rust,editable + +fn main() { + // COMPLETEAZĂ spațiul liber + let b = __; + + let _v = match b { + true => 1, + // Funcțiile divergente pot fi, de asemenea, utilizate în expresii match pentru a înlocui o valoare de orice tip. + false => { + println!("Success!"); + panic!("we have no value for `false`, but we can panic"); + } + }; + + println!("Exercise Failed if printing out this line!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice)(sub calea soluțiilor), dar utilizați-le doar atunci când aveți nevoie. diff --git a/ro-RO/src/basic-types/intro.md b/ro-RO/src/basic-types/intro.md new file mode 100644 index 000000000..ec0b69e5f --- /dev/null +++ b/ro-RO/src/basic-types/intro.md @@ -0,0 +1,5 @@ +# Tipuri de bază +Resurse de învățare: +- Engleză: [Rust Book 3.2 and 3.3](https://doc.rust-lang.org/book/ch03-02-data-types.html) +- Chineză simplificată: [Rust语言圣经 - 基本类型](https://course.rs/basic/base-type/index.html) +- Română: [] diff --git a/ro-RO/src/basic-types/numbers.md b/ro-RO/src/basic-types/numbers.md new file mode 100644 index 000000000..c433f6d80 --- /dev/null +++ b/ro-RO/src/basic-types/numbers.md @@ -0,0 +1,187 @@ +# Numere + +### Numere întregi + +1. 🌟 + +> Sfat: Dacă nu atribuim explicit un tip unei variabile, compilatorul îl va deduce pentru noi. + +```rust,editable + +// Eliminați ceva pentru a face să funcționeze +fn main() { + let x: i32 = 5; + let mut y: u32 = 5; + + y = x; + + let z = 10; // Ce tip are z ? + + println!("Success!"); +} +``` + +2. 🌟 +```rust,editable + +// Umple spațiul liber +fn main() { + let v: u16 = 38_u8 as __; + + println!("Success!"); +} +``` + +3. 🌟🌟🌟 + +> Sfat: Dacă nu atribuim explicit un tip unei variabile, compilatorul îl va deduce pentru noi. + +```rust,editable + +// Modificați `assert_eq!` pentru a face să funcționeze +fn main() { + let x = 5; + assert_eq!("u32".to_string(), type_of(&x)); + + println!("Success!"); +} + +// Obțineți tipul variabilei date, returnați o reprezentare sub formă de șir a tipului, de exemplu "i8", "u8", "i32", "u32". +fn type_of(_: &T) -> String { + format!("{}", std::any::type_name::()) +} +``` + +4. 🌟🌟 +```rust,editable + +// Completați spațiile goale pentru a face să funcționeze +fn main() { + assert_eq!(i8::MAX, __); + assert_eq!(u8::MAX, __); + + println!("Success!"); +} +``` + +5. 🌟🌟 +```rust,editable + +// Remediați erorile și panicele pentru a face să funcționeze. +fn main() { + let v1 = 251_u8 + 8; + let v2 = i8::checked_add(251, 8).unwrap(); + println!("{},{}",v1,v2); +} +``` + +6. 🌟🌟 +```rust,editable + +// Modificați `assert!` pentru a face să funcționeze +fn main() { + let v = 1_024 + 0xff + 0o77 + 0b1111_1111; + assert!(v == 1579); + + println!("Success!"); +} +``` + + +### Floating-Point +7. 🌟 + +```rust,editable + +// Completați spațiul gol pentru a face să funcționeze + +fn main() { + let x = 1_000.000_1; // ? + let y: f32 = 0.12; // f32 + let z = 0.01_f64; // f64 + + assert_eq!(type_of(&x), "__".to_string()); + println!("Success!"); +} + +fn type_of(_: &T) -> String { + format!("{}", std::any::type_name::()) +} +``` + +8. 🌟🌟 Faceți să funcționeze în două moduri distincte. + +```rust,editable + +fn main() { + assert!(0.1+0.2==0.3); + + println!("Success!"); +} +``` + +### Range +9. 🌟🌟 Două obiective: 1. Modificați `assert!` pentru a face codul să funcționeze 2. Faceți `println!` să afișeze: 97 - 122 + +```rust,editable +fn main() { + let mut sum = 0; + for i in -3..2 { + sum += i + } + + assert!(sum == -3); + + for c in 'a'..='z' { + println!("{}",c); + } +} +``` + +10. 🌟🌟 +```rust,editable + +// Umpleți spațiile goale +use std::ops::{Range, RangeInclusive}; +fn main() { + assert_eq!((1..__), Range{ start: 1, end: 5 }); + assert_eq!((1..__), RangeInclusive::new(1, 5)); + + println!("Success!"); +} +``` + +### Computations + +11. 🌟 +```rust,editable + +// Umpleți spațiile goale și rezolvați erorile +fn main() { + // Adunarea numerelor întregi + assert!(1u32 + 2 == __); + + // Scăderea numerelor întregi + assert!(1i32 - 2 == __); + assert!(1u8 - 2 == -1); + + assert!(3 * 50 == __); + + assert!(9.6 / 3.2 == 3.0); // asigură-te că 9.6 împărțit la 3.2 este egal cu 3.0; // eroare! fă-l să funcționeze + + assert!(24 % 5 == __); + // Logica booleană cu scurtcircuitare + assert!(true && false == __); + assert!(true || false == __); + assert!(!true == __); + + // Operații pe biți + println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101); + println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101); + println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101); + println!("1 << 5 is {}", 1u32 << 5); + println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice)(sub calea soluțiilor), dar utilizați-le doar atunci când aveți nevoie. diff --git a/ro-RO/src/basic-types/statements-expressions.md b/ro-RO/src/basic-types/statements-expressions.md new file mode 100644 index 000000000..afa4addb2 --- /dev/null +++ b/ro-RO/src/basic-types/statements-expressions.md @@ -0,0 +1,71 @@ +# Instrucțiuni și Expresii + +### Exemple +```rust,editable +fn main() { + let x = 5u32; + + let y = { + let x_squared = x * x; + let x_cube = x_squared * x; + + // Această expresie va fi asignată variabilei y + x_cube + x_squared + x + }; + + let z = { + + // Punctul și virgulă suprimă această expresie și () este asignat variabilei z + 2 * x; + }; + + println!("x is {:?}", x); + println!("y is {:?}", y); + println!("z is {:?}", z); +} +``` + +### Exercises +1. 🌟🌟 +```rust,editable +// Faceți să funcționeze în două moduri +fn main() { + let v = { + let mut x = 1; + x += 2 + }; + + assert_eq!(v, 3); + + println!("Success!"); +} +``` + +2. 🌟 +```rust,editable + +fn main() { + let v = (let x = 3); + + assert!(v == 3); + + println!("Success!"); +} +``` + +3. 🌟 +```rust,editable + +fn main() { + let s = sum(1 , 2); + assert_eq!(s, 3); + + println!("Success!"); +} + +fn sum(x: i32, y: i32) -> i32 { + x + y; +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice)(sub calea soluțiilor), dar utilizați-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/circle-reference/intro.md b/ro-RO/src/circle-reference/intro.md new file mode 100644 index 000000000..4f99ca561 --- /dev/null +++ b/ro-RO/src/circle-reference/intro.md @@ -0,0 +1 @@ +# Circle reference and Self referential diff --git a/ro-RO/src/collections/hashmap.md b/ro-RO/src/collections/hashmap.md new file mode 100644 index 000000000..2eef9357a --- /dev/null +++ b/ro-RO/src/collections/hashmap.md @@ -0,0 +1,225 @@ +# HashMap +În timp ce vectorii stochează valori printr-un index întreg, HashMaps stochează valori prin intermediul unei chei. Este o hartă de tip hash implementată cu sondaj pătratic și căutare SIMD. În mod implicit, HashMap utilizează un algoritm de hash selectat pentru a oferi rezistență împotriva atacurilor HashDoS. + +Algoritmul implicit de hash este în prezent SipHash 1-3, cu toate că acest lucru poate suferi modificări în orice moment în viitor. În timp ce performanța sa este foarte competitivă pentru chei de dimensiuni medii, alte algoritme de hash îl vor depăși pentru chei mici, cum ar fi cele întregi, precum și pentru chei mari, cum ar fi șiruri lungi, deși aceste algoritme nu vor oferi, de obicei, protecție împotriva atacurilor precum HashDoS. + +Implementarea tabelului de hash este o adaptare Rust a SwissTable de la Google. Versiunea originală în C++ a SwissTable poate fi găsită aici, iar acest discurs CppCon oferă o prezentare a modului în care funcționează algoritmul. + + +### Operații de bază +1. 🌟🌟 + +```rust,editable + +// UMPLEȚI spațiile goale si REZOLVAȚI erorile +use std::collections::HashMap; +fn main() { + let mut scores = HashMap::new(); + scores.insert("Sunface", 98); + scores.insert("Daniel", 95); + scores.insert("Ashley", 69.0); + scores.insert("Katie", "58"); + + // `Get` întoarce Option<&V> + let score = scores.get("Sunface"); + assert_eq!(score, Some(98)); + + if scores.contains_key("Daniel") { + // Indexarea returnează o valoare V + let score = scores["Daniel"]; + assert_eq!(score, __); + scores.remove("Daniel"); + } + + assert_eq!(scores.len(), __); + + for (name, score) in scores { + println!("The score of {} is {}", name, score); + } +} +``` + +2. 🌟🌟 +```rust,editable + +use std::collections::HashMap; +fn main() { + let teams = [ + ("Chinese Team", 100), + ("American Team", 10), + ("France Team", 50), + ]; + + let mut teams_map1 = HashMap::new(); + for team in &teams { + teams_map1.insert(team.0, team.1); + } + + // IMPLEMENTAȚI team_map2 in două moduri + // Sfat: o posibilă abordare ar fi folosirea metodei `collect` + let teams_map2... + + assert_eq!(teams_map1, teams_map2); + + println!("Success!"); +} +``` + +3. 🌟🌟 +```rust,editable + +// UMPLEȚI spațiile goale +use std::collections::HashMap; +fn main() { + // Inferența de tip ne permite să omitem o semnătură explicită de tip + // (care ar fi HashMap<&str, u8> în acest exemplu). + let mut player_stats = HashMap::new(); + + // Introduce o cheie doar dacă aceasta nu există deja. + player_stats.entry("health").or_insert(100); + + assert_eq!(player_stats["health"], __); + + // Introduce o cheie folosind o funcție care furnizează o valoare nouă + // doar dacă aceasta nu există deja. + player_stats.entry("health").or_insert_with(random_stat_buff); + assert_eq!(player_stats["health"], __); + + // Se asigură că o valoare este în intrare prin introducerea valorii implicite dacă este goală + // și returnează o referință mutabilă la valoarea din intrare. + let health = player_stats.entry("health").or_insert(50); + assert_eq!(health, __); + *health -= 50; + assert_eq!(*health, __); + + println!("Success!"); +} + +fn random_stat_buff() -> u8 { + // Ar putea returna efectiv o valoare aleatoare aici + // să returnăm pur și simplu o valoare fixă pentru moment. + 42 +} +``` + +### Cerințe pentru cheile HashMap +Orice tip care implementează trăsăturile Eq și Hash poate fi o cheie în HashMap. Aceasta include: + +- bool (deși nu foarte util deoarece există doar două chei posibile) +- int, uint și toate variațiile acestora +- String și &str (sugestie: poți avea o HashMap indexată cu String și apela .get() cu un &str) + +Observați că f32 și f64 nu implementează Hash, probabil din cauza problemelor de precizie cu numere în virgulă mobilă care ar face folosirea lor ca chei într-o hartă hash extrem de predispusă la erori. + +Toate clasele de colecții implementează Eq și Hash dacă tipul lor conținut implementează, de asemenea, Eq și Hash. De exemplu, Vec va implementa Hash dacă T implementează Hash. + +4. 🌟🌟 +```rust,editable + +// CORECTEAZĂ erorile +// Sfaturi: derive este de obicei o modalitate bună de a implementa unele trăsături folosite frecvent +use std::collections::HashMap; + +struct Viking { + name: String, + country: String, +} + +impl Viking { + /// Creates a new Viking. + fn new(name: &str, country: &str) -> Viking { + Viking { + name: name.to_string(), + country: country.to_string(), + } + } +} + +fn main() { + // Folosește o HashMap pentru a stoca punctele de viață ale vikingilor. + let vikings = HashMap::from([ + (Viking::new("Einar", "Norway"), 25), + (Viking::new("Olaf", "Denmark"), 24), + (Viking::new("Harald", "Iceland"), 12), + ]); + + // Folosește implementarea derivată pentru a afișa starea vikingilor. + for (viking, health) in &vikings { + println!("{:?} has {} hp", viking, health); + } +} +``` + +### Capacitate +La fel ca vectorii, HashMaps sunt extensibili, dar acestea se pot și micșora atunci când au spațiu în exces. Puteți crea un HashMap cu o anumită capacitate inițială folosind HashMap::with_capacity(uint), sau puteți utiliza HashMap::new() pentru a obține un HashMap cu o capacitate inițială implicită (recomandată). + +#### Exemplu +```rust,editable + +use std::collections::HashMap; +fn main() { + let mut map: HashMap = HashMap::with_capacity(100); + map.insert(1, 2); + map.insert(3, 4); + // Într-adevăr, capacitatea HashMap nu este 100, așa că nu putem compara egalitatea aici. + assert!(map.capacity() >= 100); + + // Micșorează capacitatea hărții cu o limită inferioară. + // Nu va scădea mai jos decât limita furnizată, păstrând în același timp regulile interne + // și, posibil, lăsând spațiu conform politicii de redimensionare. + + map.shrink_to(50); + assert!(map.capacity() >= 50); + + // Micșorează capacitatea hărții cât mai mult posibil. + // Va scădea cât mai mult posibil, păstrând în același timp regulile interne + // și, posibil, lăsând spațiu conform politicii de redimensionare. + map.shrink_to_fit(); + assert!(map.capacity() >= 2); + println!("Success!"); +} +``` + +### Proprietate (Ownership) +Pentru tipuri care implementează trăsătura Copy, cum ar fi i32, valorile sunt copiate în HashMap. Pentru valorile deținute precum String, valorile vor fi mutate, iar HashMap va deveni proprietarul acestora. + +5. 🌟🌟 +```rust,editable + +// CORECTEAZĂ erorile cu cel mai mic număr de modificări +// NU șterge nicio linie de cod +use std::collections::HashMap; +fn main() { + let v1 = 10; + let mut m1 = HashMap::new(); + m1.insert(v1, v1); + println!("v1 is still usable after inserting to hashmap : {}", v1); + + let v2 = "hello".to_string(); + let mut m2 = HashMap::new(); + // Proprietate (Ownership) mutată aici + m2.insert(v2, v1); + + assert_eq!(v2, "hello"); + + println!("Success!"); +} +``` + +### Biblioteci Hash terțe +Dacă performanța lui SipHash 1-3 nu îndeplinește cerințele dvs., puteți găsi înlocuitori pe crates.io sau github.com. + +Utilizarea unei funcționalități de hash terțe arată în felul următor: +```rust +use std::hash::BuildHasherDefault; +use std::collections::HashMap; + +// Introdu o funcție de hash terță parte +use twox_hash::XxHash64; + + +let mut hash: HashMap<_, _, BuildHasherDefault> = Default::default(); +hash.insert(42, "the answer"); +assert_eq!(hash.get(&42), Some(&"the answer")); +``` + diff --git a/ro-RO/src/collections/intro.md b/ro-RO/src/collections/intro.md new file mode 100644 index 000000000..408e9b584 --- /dev/null +++ b/ro-RO/src/collections/intro.md @@ -0,0 +1,6 @@ +# Tipuri de colecții +Resurse de învățare: +- Engleză: [Rust Book Chapter 8](https://doc.rust-lang.org/book/ch08-00-common-collections.html) +- Chineză simplificată: [Rust语言圣经 - 集合类型](https://course.rs/basic/collections/intro.html) + + diff --git a/ro-RO/src/collections/string.md b/ro-RO/src/collections/string.md new file mode 100644 index 000000000..32917035a --- /dev/null +++ b/ro-RO/src/collections/string.md @@ -0,0 +1,206 @@ +# String +`std::string::String` este un șir extensibil codificat în UTF-8. Este cel mai comun tip de șir folosit în dezvoltarea zilnică și are proprietatea conținutului șirului. + +### Operații de bază +1. 🌟🌟 +```rust,editable + +// COMPLETAȚI spațiile goale și CORECTAȚI erorile +// 1. Nu utilizați to_string() +// 2. Nu adăugați/eliminați nicio linie de cod +fn main() { + let mut s: String = "hello, "; + s.push_str("world".to_string()); + s.push(__); + + move_ownership(s); + + assert_eq!(s, "hello, world!"); + + println!("Success!"); +} + +fn move_ownership(s: String) { + println!("ownership of \"{}\" is moved here!", s) +} +``` + +### String și &str +Un String este stocat sub formă de vector de octeți (Vec), dar este întotdeauna garantat să fie o secvență UTF-8 validă. String este alocat pe heap, poate crește dinamic și nu este terminat cu null. + +&str este o felie (&[u8]) care indică întotdeauna către o secvență UTF-8 validă și poate fi utilizat pentru a vizualiza conținutul unui String, la fel cum &[T] este o vedere într-un Vec. + +2. 🌟🌟 +```rust,editable +// COMPLETAȚI spațiile goale +fn main() { + let mut s = String::from("hello, world"); + + let slice1: &str = __; // În două moduri + assert_eq!(slice1, "hello, world"); + + let slice2 = __; + assert_eq!(slice2, "hello"); + + let slice3: __ = __; + slice3.push('!'); + assert_eq!(slice3, "hello, world!"); + + println!("Success!"); +} +``` + +3. 🌟🌟 +```rust,editable + +// Întrebare: câte alocări de heap au loc aici? +// Răspunsul tău: +fn main() { + // Creează un tip String bazat pe &str + // Tipul literalurilor de șir este &str + let s: String = String::from("hello, world!"); + + // Creează un `slice` care indică către String-ul s + let slice: &str = &s; + + + // Creează un tip String bazat pe `slice`-ul creat recent + let s: String = slice.to_string(); + + assert_eq!(s, "hello, world!"); + + println!("Success!"); +} +``` + +### UTF-8 și Indexare +Șirurile sunt întotdeauna formate din UTF-8 valid. Acest lucru are câteva implicații: + +Prima dintre acestea este că, dacă aveți nevoie de un șir non-UTF-8, luați în considerare [OsString](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html). Este similar, dar fără constrângerea UTF-8. +A doua implicație este că nu puteți indexa într-un String. +Indexarea este menită să fie o operație cu timp constant, dar encodarea UTF-8 nu ne permite să facem acest lucru. În plus, nu este clar ce fel de informație ar trebui să returneze indexul: un octet, un punct de cod sau un cluster grafemic. Metodele bytes și chars returnează iteratori peste primele două, respectiv. + +4. 🌟🌟🌟 Nu puteți folosi indexul pentru a accesa un caracter într-un șir, dar puteți utiliza felișea &s1[start..end]. + +```rust,editable + +// COMPLETAȚI spațiile goale și CORECTAȚI erorile +fn main() { + let s = String::from("hello, 世界"); + let slice1 = s[0]; // Sfaturi: h ocupă doar 1 byte în formatul UTF-8 + assert_eq!(slice1, "h"); + + let slice2 = &s[3..5]; // Sfaturi: 中 ocupă 3 octeți în formatul UTF-8 + assert_eq!(slice2, "世"); + + // Parcurgeți toate caracterele din s + for (i, c) in s.__ { + if i == 7 { + assert_eq!(c, '世') + } + } + + println!("Success!"); +} +``` + + +#### UTF8_slice +Puteți utiliza [utf8_slice](https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.html) pentru a felia un șir UTF8, acesta poate indexa caractere în loc de octeți. + +**Exemplu** +```rust +use utf8_slice; +fn main() { + let s = "The 🚀 goes to the 🌑!"; + + let rocket = utf8_slice::slice(s, 4, 5); + // Va fi egal cu "🚀" +} +``` + + +5. 🌟🌟🌟 +> Sfat: poate aveți nevoie de metoda from_utf8 + +```rust,editable + +// COMPLETAȚI spațiile goale +fn main() { + let mut s = String::new(); + __; + + // Niste octeți într-un vector. + let v = vec![104, 101, 108, 108, 111]; + + // Transformă un vector de octeți într-un șir de caractere (String) + let s1 = __; + + + assert_eq!(s, s1); + + println!("Success!"); +} +``` + +### Reprezentare +Un șir de caractere (String) este compus din trei componente: un pointer către niște octeți, o lungime și o capacitate. + +Pointer-ul arată către un buffer intern pe care String îl folosește pentru a stoca datele sale. Lungimea reprezintă numărul de octeți stocați în prezent în buffer (întotdeauna stocați în heap), iar capacitatea este dimensiunea buffer-ului în octeți. Prin urmare, lungimea va fi întotdeauna mai mică sau egală cu capacitatea. + +6. 🌟🌟 Dacă un String are suficientă capacitate, adăugarea de elemente la el nu va realoca memorie. +```rust,editable + +// Modificați codul de mai jos pentru a afișa +// 25 +// 25 +// 25 +// Aici nu este nevoie să alocăm mai multă memorie în interiorul buclei. +fn main() { + let mut s = String::new(); + + println!("{}", s.capacity()); + + for _ in 0..2 { + s.push_str("hello"); + println!("{}", s.capacity()); + } + + println!("Success!"); +} +``` + +7. 🌟🌟🌟 +```rust,editable + +// UMPLEȚI spațiile goale +use std::mem; + +fn main() { + let story = String::from("Rust By Practice"); + + // Împiedică eliminarea automată a datelor din String + let mut story = mem::ManuallyDrop::new(story); + + let ptr = story.__(); + let len = story.__(); + let capacity = story.__(); + + assert_eq!(16, len); + + // Putem reconstrui un String folosind ptr, len și capacity. + // Totul este nesigur, deoarece suntem responsabili să ne asigurăm că + // componentele sunt valide: + let s = unsafe { String::from_raw_parts(ptr, len, capacity) }; + + assert_eq!(*story, s); + + println!("Success!"); +} +``` + + +### Metode comune +Mai multe exerciții despre metodele String pot fi găsite [aici](../std/String.md). + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/collections/vector.md b/ro-RO/src/collections/vector.md new file mode 100644 index 000000000..0029f35f5 --- /dev/null +++ b/ro-RO/src/collections/vector.md @@ -0,0 +1,244 @@ +# Vector +Vectorii sunt tablouri redimensionabile. La fel ca și slice-urile, dimensiunea lor nu este cunoscută în timpul compilării, dar pot să crească sau să scadă în orice moment. + + +### Operații de bază +1. 🌟🌟🌟 +```rust,editable + +fn main() { + let arr: [u8; 3] = [1, 2, 3]; + + let v = Vec::from(arr); + is_vec(&v); + + let v = vec![1, 2, 3]; + is_vec(&v); + + // vec!(..) și vec![..] sunt aceleași macrocomenzi, deci + let v = vec!(1, 2, 3); + is_vec(&v); + + // În cod-ul de mai jos, v este Vec<[u8; 3]>, nu Vec + // FOLOSIȚI Vec::new și `for` pentru a rescrie codul de mai jos + let v1 = vec!(arr); + is_vec(&v1); + + assert_eq!(v, v1); + + println!("Success!"); +} + +fn is_vec(v: &Vec) {} +``` + + + +2. 🌟🌟 Un vector poate fi extins cu metoda `extend` +```rust,editable + +// UMPLEȚI spațiile goale +fn main() { + let mut v1 = Vec::from([1, 2, 4]); + v1.pop(); + v1.push(3); + + let mut v2 = Vec::new(); + v2.__; + + assert_eq!(v1, v2); + + println!("Success!"); +} +``` + +### Transformați X în Vec +3. 🌟🌟🌟 +```rust,editable + +// UMPLEȚI spațiile goale +fn main() { + // Array -> Vec + // impl From<[T; N]> pentru Vec + let arr = [1, 2, 3]; + let v1 = __(arr); + let v2: Vec = arr.__(); + + assert_eq!(v1, v2); + + + // String -> Vec + // impl From pentru Vec + let s = "hello".to_string(); + let v1: Vec = s.__(); + + let s = "hello".to_string(); + let v2 = s.into_bytes(); + assert_eq!(v1, v2); + + // impl<'_> From<&'_ str> pentru Vec + let s = "hello"; + let v3 = Vec::__(s); + assert_eq!(v2, v3); + + // Iteratoarele pot fi colectate în vectori + let v4: Vec = [0; 10].into_iter().collect(); + assert_eq!(v4, vec![0; 10]); + + println!("Success!"); + } +``` + +### Indexarea +4. 🌟🌟🌟 +```rust,editable + +// REZOLVAȚI erorile și IMPLEMENTAȚI codul +fn main() { + let mut v = Vec::from([1, 2, 3]); + for i in 0..5 { + println!("{:?}", v[i]) + } + + for i in 0..5 { + // IMPLEMENTAȚI codul aici... + } + + assert_eq!(v, vec![2, 3, 4, 5, 6]); + + println!("Success!"); +} +``` + + +### Felii (Slicing) +Un Vec poate fi mutabil. Pe de altă parte, slice-urile sunt obiecte doar pentru citire. Pentru a obține un slice, folosiți &. + +În Rust, este mai obișnuit să se transmită slice-uri ca argumente în loc de vectori atunci când doriți doar să furnizați acces de citire. Același lucru este valabil pentru String și &str. + +5. 🌟🌟 +```rust,editable + +// REZOLVAȚI erorile +fn main() { + let mut v = vec![1, 2, 3]; + + let slice1 = &v[..]; + // Accesul în afara limitelor va cauza o panică + // Trebuie să utilizați v.len aici + let slice2 = &v[0..4]; + + assert_eq!(slice1, slice2); + + // Slice-urile sunt doar pentru citire + // Notă: slice-urile și &Vec sunt diferite + let vec_ref: &mut Vec = &mut v; + (*vec_ref).push(4); + let slice3 = &mut v[0..3]; + slice3.push(4); + + assert_eq!(slice3, &[1, 2, 3, 4]); + + println!("Success!"); +} +``` +### Capacitate +Capacitatea unui vector reprezintă spațiul alocat pentru orice elemente viitoare care vor fi adăugate la vector. Aceasta nu trebuie confundată cu lungimea unui vector, care specifică numărul real de elemente din vector. Dacă lungimea unui vector depășește capacitatea sa, capacitatea acestuia va fi crescută automat, dar elementele vor trebui să fie realocate. + +De exemplu, un vector cu o capacitate de 10 și o lungime de 0 ar fi un vector gol cu spațiu pentru încă 10 elemente. Adăugarea a 10 sau mai puține elemente în vector nu va schimba capacitatea sau nu va provoca realocare. Cu toate acestea, dacă lungimea vectorului este crescută la 11, va trebui să fie realocat, ceea ce poate fi lent. Din acest motiv, se recomandă utilizarea Vec::with_capacity ori de câte ori este posibil pentru a specifica cât de mare se așteaptă să devină vectorul. + +6. 🌟🌟 +```rust,editable +// REZOLVAȚI erorile +fn main() { + let mut vec = Vec::with_capacity(10); + + // Vectorul nu conține niciun element, chiar dacă are capacitate pentru mai multe. + assert_eq!(vec.len(), __); + assert_eq!(vec.capacity(), 10); + + // Toate acestea se fac fără a realoca memorie... + for i in 0..10 { + vec.push(i); + } + assert_eq!(vec.len(), __); + assert_eq!(vec.capacity(), __); + + // ...dar acest lucru ar putea determina vectorul să realoce memorie. + vec.push(11); + assert_eq!(vec.len(), 11); + assert!(vec.capacity() >= 11); + + // Completați cu o valoare potrivită pentru a face ca bucla for să se execute fără alocare suplimentară de memorie + let mut vec = Vec::with_capacity(__); + for i in 0..100 { + vec.push(i); + } + + assert_eq!(vec.len(), __); + assert_eq!(vec.capacity(), __); + + println!("Success!"); +} +``` + +### Stocarea de tipuri distincte într-un Vector +Elementele dintr-un vector trebuie să fie de același tip. De exemplu, codul de mai jos va genera o eroare: +```rust +fn main() { + let v = vec![1, 2.0, 3]; +} +``` + +Dar putem folosi enum-uri sau obiecte de tip trait pentru a stoca tipuri distincte. + +7. 🌟🌟 +```rust,editable +#[derive(Debug)] +enum IpAddr { + V4(String), + V6(String), +} +fn main() { + // COMPLETAȚI spațiul liber + let v : Vec= __; + + // Pentru a compara două enum-uri, este necesar să derivăm traitul PartialEq. + assert_eq!(v[0], IpAddr::V4("127.0.0.1".to_string())); + assert_eq!(v[1], IpAddr::V6("::1".to_string())); + + println!("Success!"); +} +``` + +8. 🌟🌟 +```rust,editable +trait IpAddr { + fn display(&self); +} + +struct V4(String); +impl IpAddr for V4 { + fn display(&self) { + println!("ipv4: {:?}",self.0) + } +} +struct V6(String); +impl IpAddr for V6 { + fn display(&self) { + println!("ipv6: {:?}",self.0) + } +} + +fn main() { + // COMPLETAȚI spațiul liber + let v: __= vec![ + Box::new(V4("127.0.0.1".to_string())), + Box::new(V6("::1".to_string())), + ]; + + for ip in v { + ip.display(); + } +} +``` diff --git a/ro-RO/src/comments-docs.md b/ro-RO/src/comments-docs.md new file mode 100644 index 000000000..afef0fa10 --- /dev/null +++ b/ro-RO/src/comments-docs.md @@ -0,0 +1,295 @@ +# Comments and Docs +Every program requires comments: + + +## Comments +- Regular comments which are ignored by the compiler: + - `// Line comment, which goes to the end of the line` + - `/* Block comment, which goes to the end of the closing delimiter */` + + +### Examples +```rust +fn main() { + // This is an example of a line comment + // There are two slashes at the beginning of the line + // And nothing written inside these will be read by the compiler + + // println!("Hello, world!"); + + // Run it. See? Now try deleting the two slashes, and run it again. + + /* + * This is another type of comment, a block comment. In general, + * line comments are the recommended comment style. But + * block comments are extremely useful for temporarily disabling + * chunks of code. /* Block comments can be /* nested, */ */ + * so it takes only a few keystrokes to comment out everything + * in this main() function. /*/*/* Try it yourself! */*/*/ + */ + + /* + Note: The previous column of `*` was entirely for style. There's + no actual need for it. + */ +} +``` + +### Exercises +1. 🌟🌟 +```rust,editable + +/* Make it work, only using comments! */ +fn main() { + todo!(); + unimplemented!(); + + assert_eq!(6, 5 + 3 + 2 + 1 ) +} +``` + + +## Doc Comments +- Doc comments which are parsed into HTML and supported `Markdown` + - `/// Generate library docs for the following item` + - `//! Generate library docs for the eclosing item` + +Before starting, we need to create a new package for practice: `cargo new --lib doc-comments`. + + +### Line doc comments `///` +Add docs for function `add_one` +```rust +// in lib.rs + +/// Add one to the given value and return the value +/// +/// # Examples +/// +/// ``` +/// let arg = 5; +/// let answer = my_crate::add_one(arg); +/// +/// assert_eq!(6, answer); +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} +``` + +### Cargo doc +We can use `cargo doc --open` to generate html files and open them in the browser. + +### Block doc comments `/** ... */` +Add docs for function `add_two`: +```rust +/** Add two to the given value and return a new value + +# Examples + +let arg = 5; +let answer = my_crate::add_two(arg); + +assert_eq!(7, answer); + +*/ +pub fn add_two(x: i32) -> i32 { + x + 2 +} +``` + +### Doc comments for crate and module +We can also add doc comments for our crates and modules. + +Firstly, let's add some doc comments for our library crate: + +> Note: We must place crates and module comments at the top of crate root or module file. +```rust +//! # Doc comments +//! +//! A library for showing how to use doc comments + +// in lib.rs +pub mod compute; +``` + +You can also use block comments to achieve this: +```rust +/*! # Doc comments + + A library for showing how to use doc comments */ +``` + +Next, create a new module file `src/compute.rs`, and add following comments to it: +```rust +//! //! Do some complicated arithmetic that you can't do by yourself + +// in compute.rs +``` + +Then run `cargo doc --open` and see the results. + + +### Doc tests +The doc comments of `add_one` and `add_two` contain two example code blocks. + +The examples can not only demonstrate how to use your library, but also running as test with `cargo test` command. + +2. 🌟🌟 But there are errors in the two examples, please fix them, and running with `cargo test` to get following result: +```shell +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests doc-comments + +running 2 tests +test src/lib.rs - add_one (line 11) ... ok +test src/lib.rs - add_two (line 26) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s +``` + +3. 🌟🌟 Sometimes we expect an example to be panic, add following code to `src/compute.rs` and make the `cargo test` passed. + +> You can only modify the comments, DON'T modify `fn div` + +```rust +// in src/compute.rs + +/// # Panics +/// +/// The function panics if the second argument is zero. +/// +/// ```rust,should_panic +/// // panics on division by zero +/// doc_comments::compute::div(10, 0); +/// ``` +pub fn div(a: i32, b: i32) -> i32 { + if b == 0 { + panic!("Divide-by-zero error"); + } + + a / b +} +``` + +4. 🌟🌟 Sometimes we want to hide the doc comments, but keep the doc tests. + +Add following code to `src/compute.rs` , + +```rust +// in src/compute.rs + +/// ``` +/// # fn try_main() -> Result<(), String> { +/// # let res = doc_comments::compute::try_div(10, 0)?; +/// # Ok(()) // returning from try_main +/// # } +/// # fn main() { +/// # try_main().unwrap(); +/// # +/// # } +/// ``` +pub fn try_div(a: i32, b: i32) -> Result { + if b == 0 { + Err(String::from("Divide-by-zero")) + } else { + Ok(a / b) + } +} +``` + +and modify this code to achieve two goals: + +- The doc comments must not be presented in html files generated by `cargo doc --open` +- run the tests, you should see results as below: + +```shell +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests doc-comments + +running 4 tests +test src/compute.rs - compute::div (line 7) ... ok +test src/lib.rs - add_two (line 27) ... ok +test src/lib.rs - add_one (line 11) ... ok +test src/compute.rs - compute::try_div (line 20) ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.51s +``` + +### Code navigation +Rust provide a very powerful feature for us, that is code navigation in doc comments. + +Add following code to `src/lib.rs`: +```rust +// in lib.rs + +/// Add three to the given value and return a [`Option`] type +pub fn add_three(x: i32) -> Option { + Some(x + 3) +} +``` + +Besides jump into the standard library, you can also jump to another module in the package. + +```rust +// in lib.rs + +mod a { + /// Add four to the given value and return a [`Option`] type + /// [`crate::MySpecialFormatter`] + pub fn add_four(x: i32) -> Option { + Some(x + 4) + } +} + +struct MySpecialFormatter; +``` + +### Doc attributes +Below are a few examples of the most common `#[doc]` attributes used with `rustdoc`. + +### `inline` + +Used to inline docs, instead of linking out to separate page. + +```rust,ignore +#[doc(inline)] +pub use bar::Bar; + +/// bar docs +mod bar { + /// the docs for Bar + pub struct Bar; +} +``` + +### `no_inline` + +Used to prevent linking out to separate page or anywhere. + +```rust,ignore +// Example from libcore/prelude +#[doc(no_inline)] +pub use crate::mem::drop; +``` + +### `hidden` + +Using this tells `rustdoc` not to include this in documentation: + +```rust,editable,ignore +// Example from the futures-rs library +#[doc(hidden)] +pub use self::async_await::*; +``` + +For documentation, `rustdoc` is widely used by the community. It's what is used to generate the [std library docs](https://doc.rust-lang.org/std/). + + +### Full Code +The full code of package `doc-comments` is [here](https://github.com/sunface/rust-by-practice/tree/master/practices/doc-comments). diff --git a/ro-RO/src/compound-types/array.md b/ro-RO/src/compound-types/array.md new file mode 100644 index 000000000..eacdff74a --- /dev/null +++ b/ro-RO/src/compound-types/array.md @@ -0,0 +1,102 @@ +# Tablou (Array) +Tipul de tablou este [T; Lungime], așa cum poți observa, lungimea tabloului este parte a semnăturii lor de tip. Prin urmare, lungimea lor trebuie să fie cunoscută în timpul compilării. + +De exemplu, nu poți inițializa un tablou în felul următor: +```rust +fn init_arr(n: i32) { + let arr = [1; n]; +} +``` + +Acest lucru va provoca o eroare, deoarece compilatorul nu are nicio idee despre dimensiunea exactă a tabloului în timpul compilării. + +1. 🌟 +```rust,editable + +fn main() { + // Completează spațiul gol cu tipul de tablou potrivit + let arr: __ = [1, 2, 3, 4, 5]; + + // Modifică codul de mai jos pentru a-l face funcțional + assert!(arr.len() == 4); + + println!("Success!"); +} +``` + +2. 🌟🌟 +```rust,editable + +fn main() { + // Putem să ignorăm părți ale tipului de tablou sau chiar întregul tip, să lăsăm compilatorul să-l deducă pentru noi + let arr0 = [1, 2, 3]; + let arr: [_; 3] = ['a', 'b', 'c']; + + // Completează spațiul gol + // Tablourile sunt alocate pe stivă, std::mem::size_of_val returnează numărul de octeți pe care îi ocupă un tablou + // Un caracter în Rust ocupă 4 octeți: caracter Unicode + assert!(std::mem::size_of_val(&arr) == __); + + println!("Success!"); +} +``` + +3. 🌟 Toate elementele dintr-un tablou pot fi inițializate la aceeași valoare în același timp. + +```rust,editable + +fn main() { + // Completează spațiul gol + let list: [i32; 100] = __ ; + + assert!(list[0] == 1); + assert!(list.len() == 100); + + println!("Success!"); +} +``` + +4. 🌟 Toate elementele dintr-un tablou trebuie să fie de același tip. +```rust,editable + +fn main() { + // Remediază eroarea + let _arr = [1, 2, '3']; + + println!("Success!"); +} +``` + +5. 🌟 Indexarea începe de la 0. +```rust,editable + +fn main() { + let arr = ['a', 'b', 'c']; + + let ele = arr[1]; // Modifică doar această linie pentru a face ca codul să funcționeze! + + assert!(ele == 'a'); + + println!("Success!"); +} +``` + +6. 🌟 Out of bounds indexing causes `panic`. +```rust,editable + +// Remediază eroarea +fn main() { + let names = [String::from("Sunfei"), "Sunface".to_string()]; + + // Get returnează un Option, este sigur să-l folosești + let name0 = names.get(0).unwrap(); + + // Dar indexarea nu este sigură + let _name1 = &names[2]; + + println!("Success!"); +} + +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/compound-types/enum.md b/ro-RO/src/compound-types/enum.md new file mode 100644 index 000000000..5b8dbcbb5 --- /dev/null +++ b/ro-RO/src/compound-types/enum.md @@ -0,0 +1,209 @@ +# Enum +1. 🌟🌟 Enum-urile pot fi create cu un discriminator explicit. + +```rust,editable + +// Rezolvați erorile +enum Number { + Zero, + One, + Two, +} + +enum Number1 { + Zero = 0, + One, + Two, +} + +// Enum de tip C +enum Number2 { + Zero = 0.0, + One = 1.0, + Two = 2.0, +} + + +fn main() { + // O variantă enum poate fi convertită la un întreg folosind as + assert_eq!(Number::One, Number1::One); + assert_eq!(Number1::One, Number2::One); + + println!("Success!"); +} +``` + +2. 🌟 Fiecare variantă de enum poate deține propriile sale date. +```rust,editable + +// Completați spațiul liber +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} + +fn main() { + let msg1 = Message::Move{__}; // Instanțiere cu x = 1, y = 2 + let msg2 = Message::Write(__); // Instanțiere cu "hello, world!" + + println!("Success!"); +} +``` + +3. 🌟🌟 Putem obține datele pe care o variantă enum le deține prin potrivirea de modele. +```rust,editable + +// Completați spațiul liber și remediați eroarea +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} + +fn main() { + let msg = Message::Move{x: 1, y: 2}; + + if let Message::Move{__} = msg { + assert_eq!(a, b); + } else { + panic!("NEVER LET THIS RUN!"); + } + + println!("Success!"); +} +``` + +4. 🌟🌟 + +```rust,editable + +// Completați spațiul liber și remediați erorile +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} + +fn main() { + let msgs: __ = [ + Message::Quit, + Message::Move{x:1, y:3}, + Message::ChangeColor(255,255,0) + ]; + + for msg in msgs { + show_message(msg) + } +} + +fn show_message(msg: Message) { + println!("{}", msg); +} +``` + +5. 🌟🌟 Deoarece nu există null în Rust, trebuie să folosim enum-ul Option pentru a gestiona cazurile în care valoarea lipsește. +```rust,editable + +// Completați spațiul liber pentru a face funcționarea println. +// Adăugați, de asemenea, un cod pentru a preveni rularea panic. +fn main() { + let five = Some(5); + let six = plus_one(five); + let none = plus_one(None); + + if let __ = six { + println!("{}", n); + + println!("Success!"); + } + + panic!("NEVER LET THIS RUN!"); +} + +fn plus_one(x: Option) -> Option { + match x { + __ => None, + __ => Some(i + 1), + } +} +``` + + +6. 🌟🌟🌟🌟 Implementați o `linked list`` prin intermediul enum-urilor. + +```rust,editable + +use crate::List::*; + +enum List { + // Cons: Structură tuplu care înconjoară un element și un pointer către următorul nod + Cons(u32, Box), + // Nil: Un nod care semnifică sfârșitul listei legate + Nil, +} + +// Metodele pot fi atașate unui enum +impl List { + // Creați o listă goală + fn new() -> List { + // `Nil` are tipul `List` + Nil + } + + // Consumați o listă și returnați aceeași listă cu un element nou la începutul ei + fn prepend(self, elem: u32) -> __ { + // Cons are, de asemenea, tipul List + Cons(elem, Box::new(self)) + } + + // Returnați lungimea listei + fn len(&self) -> u32 { + // self trebuie potrivit, deoarece comportamentul acestei metode depinde de variantă self + // self are tipul &List, și *self are tipul List, potrivirea pe un tip concret T este preferată față de o potrivire pe o referință &T + // După Rust 2018, puteți utiliza self aici și tail (fără ref) mai jos, de asemenea, + // Rust va deduce &-urile și ref-ul pentru voi. + // Vezi https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/default-match-bindings.html + match *self { + // Nu putem prelua proprietatea cozii, deoarece self este împrumutat; + // În schimb, preluați o referință la coadă + Cons(_, ref tail) => 1 + tail.len(), + // Caz de bază: O listă goală are lungimea zero + Nil => 0 + } + } + + // Returnați reprezentarea listei ca un șir (alocat pe heap) + fn stringify(&self) -> String { + match *self { + Cons(head, __ tail) => { + // format! este similar cu print!, dar + // returnează un șir alocat pe heap în loc să imprime la consolă + format!("{}, {}", head, tail.__()) + }, + Nil => { + format!("Nil") + }, + } + } +} + +fn main() { + // Creează o listă simplu înlănțuită goală + let mut list = List::new(); + + // Adaugă elemente înainte (la începutul listei) + list = list.prepend(1); + list = list.prepend(2); + list = list.prepend(3); + + // Afișează starea finală a listei + println!("linked list has length: {}", list.len()); + println!("{}", list.stringify()); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/compound-types/intro.md b/ro-RO/src/compound-types/intro.md new file mode 100644 index 000000000..3f986ca2a --- /dev/null +++ b/ro-RO/src/compound-types/intro.md @@ -0,0 +1,6 @@ +# Tipuri compuse +Resurse de învățare: +- Engleză:: [Rust Book 4.3, 5.1, 6.1, 8.2](https://doc.rust-lang.org/book/ch04-03-slices.html) +- Chineză simplificată: [Rust语言圣经 - 复合类型](https://course.rs/basic/compound-type/intro.html) + + diff --git a/ro-RO/src/compound-types/slice.md b/ro-RO/src/compound-types/slice.md new file mode 100644 index 000000000..260bd7c0a --- /dev/null +++ b/ro-RO/src/compound-types/slice.md @@ -0,0 +1,100 @@ +# Felie (Slice) +Feliile sunt similare cu tablourile, dar lungimea lor nu este cunoscută în timpul compilării, așa că nu poți utiliza feliile direct. + +1. 🌟🌟 Aici, atât [i32] cât și str sunt tipuri de felii, dar utilizarea directă va provoca erori. Trebuie să folosiți referința feliei în schimb: &[i32], &str. +```rust,editable + +// Remediază erorile, NU adăuga noi linii! +fn main() { + let arr = [1, 2, 3]; + let s1: [i32] = arr[0..2]; + + let s2: str = "hello, world" as str; + + println!("Success!"); +} +``` + +O referință la o felie este un obiect format din două cuvinte, din motive de simplitate, de acum înainte vom folosi doar "felia" în loc de "referința la felie". Primul cuvânt este un pointer către date, iar al doilea cuvânt este lungimea feliei. Dimensiunea cuvântului este aceeași cu usize, determinată de arhitectura procesorului, de exemplu, 64 de biți pe un x86-64. Feliile pot fi utilizate pentru a împrumuta o secțiune a unui tablou și au semnătura de tip &[T]. + +2. 🌟🌟🌟 +```rust,editable + +fn main() { + let arr: [char; 3] = ['中', '国', '人']; + + let slice = &arr[..2]; + + // Modifică '8' pentru a face codul să funcționeze + // SFAT: slice (referința la feliu) NU ESTE un tablou, dacă ar fi un tablou, atunci assert! ar fi trecut: Fiecare dintre cele două caractere '中' și '国' ocupă 4 octeți, 2 * 4 = 8 + assert!(std::mem::size_of_val(&slice) == 8); + + println!("Success!"); +} +``` + +3. 🌟🌟 +```rust,editable + +fn main() { + let arr: [i32; 5] = [1, 2, 3, 4, 5]; + // Completează spațiile goale pentru a face codul să funcționeze + let slice: __ = __; + assert_eq!(slice, &[2, 3, 4]); + + println!("Success!"); +} +``` + +### Feliile de șiruri (String slices) +4. 🌟 +```rust,editable + +fn main() { + let s = String::from("hello"); + + let slice1 = &s[0..2]; + // Completează spațiul gol pentru a face codul să funcționeze, NU FOLOSI 0..2 din nou + let slice2 = &s[__]; + + assert_eq!(slice1, slice2); + + println!("Success!"); +} +``` + +5. 🌟 +```rust,editable + +fn main() { + let s = "你好,世界"; + // Modifică această linie pentru a face codul să funcționeze + let slice = &s[0..2]; + + assert!(slice == "你"); + + println!("Success!"); +} +``` + +6. 🌟🌟 `&String` can be implicitly converted into `&str`. +```rust,editable + +// Remediază erorile +fn main() { + let mut s = String::from("hello world"); + + // Aici, &s are tipul &String, dar first_word necesită un tip &str. + // Funcționează deoarece &String poate fi convertit implicit la &str. Dacă vrei să afli mai multe, acest lucru se numește "coerciție Deref". + let word = first_word(&s); + + s.clear(); // eroare! + + println!("the first word is: {}", word); +} +fn first_word(s: &str) -> &str { + &s[..1] +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/compound-types/string.md b/ro-RO/src/compound-types/string.md new file mode 100644 index 000000000..be0df71aa --- /dev/null +++ b/ro-RO/src/compound-types/string.md @@ -0,0 +1,268 @@ +# Șir de caractere (String) +Tipul literalului de șir "hello, world" este &str, de exemplu let s: &str = "hello, world". + + +### Str și &str +1. 🌟 Nu putem utiliza tipul str în moduri normale, dar putem utiliza &str. + +```rust,editable + +// Remedierează eroarea fără a adăuga noi linii +fn main() { + let s: str = "hello, world"; + + println!("Success!"); +} +``` + + +2. 🌟🌟 Putem utiliza doar str prin împachetarea acestuia, & poate fi folosit pentru a converti Box în &str. + +```rust,editable + +// Remediază eroarea cu cel puțin două soluții +fn main() { + let s: Box = "hello, world".into(); + greetings(s) +} + +fn greetings(s: &str) { + println!("{}",s) +} +``` + +### String +Tipul String este definit în std și stocat ca un vector de octeți (Vec), dar este întotdeauna garantat să fie o secvență UTF-8 validă. String este alocat pe stivă, poate crește și nu este terminat cu null. + +3. 🌟 +```rust,editable + +// Completează spațiul gol +fn main() { + let mut s = __; + s.push_str("hello, world"); + s.push('!'); + + assert_eq!(s, "hello, world!"); + + println!("Success!"); +} +``` + +4. 🌟🌟🌟 +```rust,editable + +// Remediază toate erorile fără a adăuga linii noi +fn main() { + let s = String::from("hello"); + s.push(','); + s.push(" world"); + s += "!".to_string(); + + println!("{}", s); +} +``` + +5. 🌟🌟 Funcția replace poate fi folosită pentru a înlocui o subșir. +```rust,editable + +// Completează spațiul gol +fn main() { + let s = String::from("I like dogs"); + // Alocă memorie nouă și stochează șirul modificat acolo + let s1 = s.__("dogs", "cats"); + + assert_eq!(s1, "I like cats"); + + println!("Success!"); +} +``` + +Mai multe metode pentru tipul String pot fi găsite în cadrul modulului [String](https://doc.rust-lang.org/std/string/struct.String.html). + +6. 🌟🌟 Poți concatena doar un String cu un &str, iar proprietatea String-ului poate fi transferată către o altă variabilă. + +```rust,editable + +// Remediază erorile fără a elimina nicio linie +fn main() { + let s1 = String::from("hello,"); + let s2 = String::from("world!"); + let s3 = s1 + s2; + assert_eq!(s3, "hello,world!"); + println!("{}", s1); +} +``` + +### &str și String +Contrar utilizării rare a tipului str, &str și String sunt folosite pretutindeni! + +7. 🌟🌟 &str poate fi convertit la String în două moduri: +```rust,editable + +// Remedierează eroarea cu cel puțin două soluții +fn main() { + let s = "hello, world"; + greetings(s) +} + +fn greetings(s: String) { + println!("{}", s) +} +``` + +8. 🌟🌟 Putem folosi String::from sau to_string pentru a converti un &str la String. + +```rust,editable + +// Folosește două abordări pentru a remedia eroarea și fără a adăuga o linie nouă +fn main() { + let s = "hello, world".to_string(); + let s1: &str = s; + + println!("Success!"); +} +``` + +### Escapări pentru șiruri (String escapes) +9. 🌟 +```rust,editable +fn main() { + // Poți utiliza caractere de escape pentru a scrie octeți folosind valorile lor hexadecimale + // Completează spațiul gol de mai jos pentru a afișa "I'm writing Rust" + let byte_escape = "I'm writing Ru\x73__!"; + println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape); + + // ...sau puncte de cod Unicode. + let unicode_codepoint = "\u{211D}"; + let character_name = "\"DOUBLE-STRUCK CAPITAL R\""; + + println!("Unicode character {} (U+211D) is called {}", + unicode_codepoint, character_name ); + + let long_string = "String literals + can span multiple lines. + The linebreak and indentation here \ + can be escaped too!"; + println!("{}", long_string); +} +``` + +10. 🌟🌟🌟 Uneori există prea multe caractere care trebuie evitate sau este mult mai convenabil să scrii un șir așa cum este. Aici intervin literalurile brute de șiruri (raw string literals). + +```rust,editable + +/* Completează spațiul gol și remediază erorile */ +fn main() { + let raw_str = r"Escapes don't work here: \x3F \u{211D}"; + // Modifică linia de mai sus pentru a face codul să funcționeze + assert_eq!(raw_str, "Escapes don't work here: ? ℝ"); + + // Dacă ai nevoie de ghilimele într-un șir brut, adaugă o pereche de # + let quotes = r#"And then I said: "There is no escape!""#; + println!("{}", quotes); + + // Dacă ai nevoie de "# în șirul tău, folosește mai multe # în delimitator. + // Poți folosi până la 65535 de #. + let delimiter = r###"A string with "# in it. And even "##!"###; + println!("{}", delimiter); + + // Completează spațiul gol + let long_delimiter = __; + assert_eq!(long_delimiter, "Hello, \"##\""); + + println!("Success!"); +} +``` + +### Șir de octeți (Byte string) +Vrei un șir care nu este UTF-8? (Ține minte, str și String trebuie să fie UTF-8 valide). Sau poate vrei un tablou de octeți care este în mare parte text? Șirurile de octeți te ajută! + +**Exemplu**: +```rust,editable +use std::str; + +fn main() { + // Reține că aceasta nu este de fapt un &str. + let bytestring: &[u8; 21] = b"this is a byte string"; + + // Tablourile de octeți nu au trăsătura Display, așa că afișarea lor este puțin limitată + println!("A byte string: {:?}", bytestring); + + // Șirurile de octeți pot avea caractere de escape pentru octeți... + let escaped = b"\x52\x75\x73\x74 as bytes"; + // ...Dar fără caractere de escape Unicode + // let escaped = b"\u{211D} Nu este permis"; + println!("Some escaped bytes: {:?}", escaped); + + + // Șirurile brute de octeți funcționează la fel ca și șirurile brute + let raw_bytestring = br"\u{211D} is not escaped here"; + println!("{:?}", raw_bytestring); + + // Conversia unui tablou de octeți la str poate eșua + if let Ok(my_str) = str::from_utf8(raw_bytestring) { + println!("And the same as text: '{}'", my_str); + } + + let _quotes = br#"You can also use "fancier" formatting, \ + like with normal raw strings"#; + + // Șirurile de octeți nu trebuie să fie UTF-8 + let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // "ようこそ" In SHIFT-JIS + + // Dar nu pot fi mereu convertite in `str` + match str::from_utf8(shift_jis) { + Ok(my_str) => println!("Conversion successful: '{}'", my_str), + Err(e) => println!("Conversion failed: {:?}", e), + }; +} +``` + +O detaliere mai amplă a modalităților de a scrie literale de șir și caractere de escape este dată în [capitolul 'Jetoane'](https://doc.rust-lang.org/reference/tokens.html) +a Referinței Rust. + +### Index de șiruri +11. 🌟🌟🌟 Nu puteți folosi index pentru a accesa un caracter dintr-un șir, dar puteți folosi slice `&s1[start..end]`. + +```rust,editable + +fn main() { + let s1 = String::from("hi,中国"); + let h = s1[0]; // Modificați această linie pentru a remedia eroarea, sfaturi: `h` ia doar 1 octet în format UTF8 + assert_eq!(h, "h"); + + let h1 = &s1[3..5]; // Modificați această linie pentru a remedia eroarea, sfaturi: `中` are 3 octeți în format UTF8 + assert_eq!(h1, "中"); + + println!("Success!"); +} +``` + +### Operați pe șir UTF8 +12. 🌟 +```rust,editable + +fn main() { + // Completați spațiul liber pentru a imprima fiecare caracter din „你好,世界” + for c in "你好,世界".__ { + println!("{}", c) + } +} +``` + +#### utf8_slice +Puteți folosi [utf8_slice](https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.html) pentru a tăia șirul UTF8. Poate indexa caractere în loc de octeți. + +**Exemplu** +```rust +use utf8_slice; +fn main() { + let s = "The 🚀 goes to the 🌑!"; + + let rocket = utf8_slice::slice(s, 4, 5); + // Va fi egal cu „🚀” +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. diff --git a/ro-RO/src/compound-types/struct.md b/ro-RO/src/compound-types/struct.md new file mode 100644 index 000000000..2c9435334 --- /dev/null +++ b/ro-RO/src/compound-types/struct.md @@ -0,0 +1,230 @@ +# Struct + +### Tipurile de structuri +1. 🌟 Trebuie să precizăm valori concrete pentru fiecare dintre câmpurile din struct. +```rust,editable + +// Remediați eroarea +struct Person { + name: String, + age: u8, + hobby: String +} +fn main() { + let age = 30; + let p = Person { + name: String::from("sunface"), + age, + }; + + println!("Success!"); +} +``` + +2. 🌟 Structura unității nu are câmpuri. Poate fi util atunci când trebuie să implementați o trăsătură pe un anumit tip, dar nu aveți date pe care doriți să le stocați în tipul în sine. +```rust,editable + +struct Unit; +trait SomeTrait { + // ...Unele comportamente definite aici. +} + +// Nu ne pasă de ce câmpuri sunt în Unitate, dar ne pasă de comportamentele acesteia. +// Așadar, folosim o structură fără câmpuri și implementăm unele comportamente pentru aceasta +impl SomeTrait for Unit { } +fn main() { + let u = Unit; + do_something_with_unit(u); + + println!("Success!"); +} + +// Completați spațiul liber pentru a face codul să funcționeze +fn do_something_with_unit(u: __) { } +``` + +3. 🌟🌟🌟 Structura tuplurilor arată similar cu tuplurile, are un sens adăugat pe care numele structurii o oferă, dar nu are câmpuri denumite. Este util atunci când vrei să dai un nume întregului tuplu, dar nu-ți pasă de numele câmpurilor. + +```rust,editable + +// Remediați eroarea și completați spațiile libere +struct Color(i32, i32, i32); +struct Point(i32, i32, i32); +fn main() { + let v = Point(__, __, __); + check_color(v); + + println!("Success!"); +} + +fn check_color(p: Color) { + let (x, _, _) = p; + assert_eq!(x, 0); + assert_eq!(p.1, 127); + assert_eq!(__, 255); + } +``` + +### Operarea pe structuri + +4. 🌟 Puteți face un întreg struct mutabil atunci când îl instanțiați, dar Rust nu ne permite să marchem doar anumite câmpuri ca mutabile. + +```rust,editable + +// Completați spațiul liber și remediați eroarea fără a adăuga/elimina o nouă linie +struct Person { + name: String, + age: u8, +} +fn main() { + let age = 18; + let p = Person { + name: String::from("sunface"), + age, + }; + + // Cum poți să crezi că fața solară are doar 18 ani? + p.age = 30; + + // Completați spațiul liber + __ = String::from("sunfei"); + + println!("Success!"); +} +``` + +5. 🌟 Folosind *field init sintaxa scurtă* pentru a reduce repetițiile. +```rust,editable + +// Completați spațiul liber +struct Person { + name: String, + age: u8, +} +fn main() { + println!("Success!"); +} + +fn build_person(name: String, age: u8) -> Person { + Person { + age, + __ + } +} +``` + +6. 🌟 Puteți crea instanță dintr-o altă instanță cu *sintaxă de actualizare a structurii* +```rust,editable + +// Completați spațiul liber pentru ca codul să funcționez +struct User { + active: bool, + username: String, + email: String, + sign_in_count: u64, +} +fn main() { + let u1 = User { + email: String::from("someone@example.com"), + username: String::from("sunface"), + active: true, + sign_in_count: 1, + }; + + let u2 = set_email(u1); + + println!("Success!"); +} + +fn set_email(u: User) -> User { + User { + email: String::from("contact@im.dev"), + __ + } +} +``` + +### Afișați structurile +7. 🌟🌟 Putem folosi `#[derive(Debug)]` pentru a [face un struct imprimabil](https://doc.rust-lang.org/book/ch05-02-example-structs.html?highlight= %23%5Bderive(Debug)%5D#adding-useful-functionality-with-derived-traits). + +```rust,editable + +// Completați spațiile libere pentru ca codul să funcționeze +#[__] +struct Rectangle { + width: u32, + height: u32, +} + +fn main() { + let scale = 2; + let rect1 = Rectangle { + width: dbg!(30 * scale), // Imprimați informațiile de depanare în stderr și atribuiți valoarea `30 * scale` la `width` + height: 50, + }; + + dbg!(&rect1); // Imprimă informațiile de depanare în stderr + + println!(__, rect1); // Imprimă informațiile de depanare în stdout +} +``` + +### Mutare parțială +În cadrul destructurarii unei singure variabile, pot fi utilizate în același timp atât legările de model prin mutare, cât și prin referință. Acest lucru va duce la o mutare parțială a variabilei, ceea ce înseamnă că părți ale variabilei vor fi mutate în timp ce celelalte părți rămân. Într-un astfel de caz, variabila părinte nu poate fi utilizată ulterior ca un întreg, totuși părțile care sunt doar referite (și nu sunt mutate) pot fi încă folosite. + +#### Exemplu +```rust,editable + +fn main() { + #[derive(Debug)] + struct Person { + name: String, + age: Box, + } + + let person = Person { + name: String::from("Alice"), + age: Box::new(20), + }; + + // „name” este mutat din persoană, dar se face referire la „age”. + let Person { name, ref age } = person; + + println!("The person's age is {}", age); + + println!("The person's name is {}", name); + + // Eroare! împrumut de valoare parțial mutată: se produce mutarea parțială a variabilei „person”. + //println!("The person struct is {:?}", person); + + // `person` nu poate fi folosit, dar `person.age` poate fi folosit deoarece nu este mutat + println!("The person's age from person struct is {}", person.age); +} +``` + + +#### Exerciții + +8. 🌟🌟 +```rust,editable + +// Remediați erorile pentru ca acest cod să funcționeze +#[derive(Debug)] +struct File { + name: String, + data: String, +} +fn main() { + let f = File { + name: String::from("readme.md"), + data: "Rust By Practice".to_string() + }; + + let _name = f.name; + + // modifică NUMAI această linie + println!("{}, {}, {:?}",f.name, f.data, f); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. \ No newline at end of file diff --git a/ro-RO/src/compound-types/tuple.md b/ro-RO/src/compound-types/tuple.md new file mode 100644 index 000000000..f5fa5f52d --- /dev/null +++ b/ro-RO/src/compound-types/tuple.md @@ -0,0 +1,89 @@ +# Tuplu +1. 🌟 Elementele dintr-un tuplu pot avea diferite tipuri. Semnătura de tip tuplu este `(T1, T2, ...)`, unde `T1`, `T2` sunt tipurile de membri ai tuplului. +```rust,editable + +fn main() { + let _t0: (u8,i16) = (0, -1); + // Tuples can be tuple's members + let _t1: (u8, (i16, u32)) = (0, (-1, 1)); + // Fill the blanks to make the code work + let t: (u8, __, i64, __, __) = (1u8, 2u16, 3i64, "hello", String::from(", world")); + + println!("Success!"); +} +``` + +2. 🌟 Membrii pot fi extrași din tuplu folosind indexare. +```rust,editable + +// Faceți să funcționeze +fn main() { + let t = ("i", "am", "sunface"); + assert_eq!(t.1, "sunface"); + + println!("Success!"); +} +``` + +3. 🌟 Tuplurile lungi nu pot fi imprimate +```rust,editable + +// Remediați eroarea +fn main() { + let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); + println!("too long tuple: {:?}", too_long_tuple); +} +``` + +4. 🌟 Destructurarea tuplului cu model. +```rust,editable + +fn main() { + let tup = (1, 6.4, "hello"); + + // Completați spațiul liber pentru ca codul să funcționeze + let __ = tup; + + assert_eq!(x, 1); + assert_eq!(y, "hello"); + assert_eq!(z, 6.4); + + println!("Success!"); +} +``` + +5. 🌟🌟 Destructurați sarcinile. +```rust,editable +fn main() { + let (x, y, z); + + // Completați spațiul liber + __ = (1, 2, 3); + + assert_eq!(x, 3); + assert_eq!(y, 1); + assert_eq!(z, 2); + + println!("Success!"); +} +``` + +6. 🌟🌟 Tuplurile pot fi folosite ca argumente de funcție și valori returnate +```rust,editable + +fn main() { + // Completați spațiul liber, aveți nevoie de câteva calcule aici. + let (x, y) = sum_multiply(__); + + assert_eq!(x, 5); + assert_eq!(y, 6); + + println!("Success!"); +} + +fn sum_multiply(nums: (i32, i32)) -> (i32, i32) { + (nums.0 + nums.1, nums.0 * nums.1) +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. diff --git a/ro-RO/src/crate-module/crate.md b/ro-RO/src/crate-module/crate.md new file mode 100644 index 000000000..e3a6aa942 --- /dev/null +++ b/ro-RO/src/crate-module/crate.md @@ -0,0 +1,109 @@ +# Pachet și ladă (crate) +Un pachet este un proiect pe care il creăm cu "cargo" (in general). Pachetul conține un fișier 'Cargo.toml'. + +1. 🌟 Creați un pachet cu ierarhia de mai jos +```shell +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +```toml +# in Cargo.toml +[package] +name = "hello-package" +version = "0.1.0" +edition = "2021" +``` + +> În acest pachet vom lucra pe parcursul întregului capitol! + +2. 🌟 Creați un pachet cu ierarhia de mai jos +```shell +. +├── Cargo.toml +└── src + └── lib.rs + +1 directory, 2 files +``` + +```toml +# in Cargo.toml +[package] +name = "hello-package1" +version = "0.1.0" +edition = "2021" +``` + +> Acest pachet poate fi șters datorită existenței primului. + +3. 🌟 +```rust,editable +/* Întrebare: */ + +// Î: Care este diferența dintre cele două pachete? +// R: __ +``` + + +## Crate +O ladă este un fișier binar sau o bibliotecă. Rădăcina lăzii este un fișier sursă de unde începe compilatorul Rust și formează modulul rădăcină al lăzii. + +În pachetul hello-package, există o ladă binară cu același nume ca și pachetul: hello-package, iar src/main.rs este rădăcina lăzii acestei lăzi binare. + +Similar cu 'hello-package', 'hello-package1' are, de asemenea, o ladă în el, însă acest pachet nu conține o ladă binară, ci o ladă de bibliotecă, iar src/lib.rs este rădăcina lăzii. + +4. 🌟 +```rust,editable +/* Întrebare: */ + +// Î: Care este numele lăzii de bibliotecă în pachetul hello-package1? +// R: __ +``` + + +5. 🌟🌟 Adaugă o cutie de bibliotecă pentru 'hello-package' și descrie structura sa de fișiere mai jos: +```shell,editable +# COMPLETEAZĂ spațiile libere +. +├── Cargo.lock +├── Cargo.toml +├── src +│   ├── __ +│   └── __ +``` + +După acest pas, în pachetul hello-package ar trebui să existe două cutii: o cutie binară și o cutie de bibliotecă, ambele având același nume ca și pachetul. + +6. 🌟🌟🌟 Un pachet poate conține cel mult o cutie de bibliotecă, dar poate conține oricâte cutii binare dorești plasând fișiere în directorul src/bin: fiecare fișier va fi o cutie binară separată cu același nume ca și fișierul. + +```shell,editable +# Creează un pachet care conține +# 1. trei cutii binare: hello-package, main1 și main2 +# 2. o cutie de bibliotecă +# descrie structura directorului mai jos +. +├── Cargo.toml +├── Cargo.lock +├── src +│ ├── __ +│ ├── __ +│ └── __ +│ └── __ +│ └── __ +├── tests # director pentru fișierele de teste integrate +│ └── some_integration_tests.rs +├── benches # director pentru fișierele de referință de performanță +│ └── simple_bench.rs +└── examples # director pentru fișierele de exemplu + └── simple_example.rs +``` + +Așa cum poți observa, structura pachetului de mai sus este foarte standard și este folosită pe scară largă în multe proiecte Rust. + + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/crate-module/intro.md b/ro-RO/src/crate-module/intro.md new file mode 100644 index 000000000..5e32401f1 --- /dev/null +++ b/ro-RO/src/crate-module/intro.md @@ -0,0 +1,5 @@ +# Crate și Module +Resurse de învățare: +- Engleză: [Rust Book Chapter 7](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) +- Chineză simplificată: [Rust语言圣经 - 包和模块](https://course.rs/basic/crate-module/intro.html) + diff --git a/ro-RO/src/crate-module/module.md b/ro-RO/src/crate-module/module.md new file mode 100644 index 000000000..a1a337c27 --- /dev/null +++ b/ro-RO/src/crate-module/module.md @@ -0,0 +1,195 @@ +# Module +Modulele ne permit să organizăm codul într-o cutie în grupuri pentru lizibilitate și ușurință în reutilizare. Modulele controlează, de asemenea, confidențialitatea elementelor, adică dacă un element poate fi văzut de codul extern (public) sau este doar o implementare internă și nu este disponibil pentru codul extern (privat). + + +Am creat un pachet numit hello-package în capitolul anterior și arată așa: +```shell +. +├── Cargo.toml +├── src +│   ├── lib.rs +│   └── main.rs +``` + +Acum este momentul să creăm câteva module în cutia de bibliotecă și să le utilizăm în cutia binară, să începem. + +1. 🌟🌟 Implementează modulul front_of_house bazat pe arborele de module de mai jos: +```shell +library crate root + └── front_of_house + ├── hosting + │ ├── add_to_waitlist + │ └── seat_at_table + └── serving + ├── take_order + ├── serve_order + ├── take_payment + └── complain +``` + +```rust,editable +// COMPLETEAZĂ spațiile libere +// în __.rs + +mod front_of_house { + // IMPLEMENTEAZĂ acest modul... +} +``` + + +2. 🌟🌟 Să apelăm add_to_waitlist dintr-o funcție eat_at_restaurant care se află în rădăcina cutiei de bibliotecă. + +```rust,editable +// În lib.rs + +// COMPLETEAZĂ spațiile libere și CORECTEAZĂ erorile +// Trebuie să faci ceva public cu pub pentru a asigura accesibilitatea pentru codul extern fn eat_at_restaurant() +mod front_of_house { + /* ...snip... */ +} + +pub fn eat_at_restaurant() { + // Apelează 'add_to_waitlist' cu **cale absolută**: + __.add_to_waitlist(); + + // Apelează cu **cale relativă** + __.add_to_waitlist(); +} +``` + +3. 🌟🌟 Poți folosi 'super' pentru a importa elemente în cadrul modulului părinte +```rust,editable +// În lib.rs + +mod back_of_house { + fn fix_incorrect_order() { + cook_order(); + // COMPLETEAZĂ spațiul liber în trei moduri + // 1. folosind cuvântul cheie 'super' + // 2. folosind calea absolută + __.serve_order(); + } + + fn cook_order() {} +} +``` + + +### Separarea modulelor în fișiere diferite +```rust,editable +// În lib.rs +pub mod front_of_house { + pub mod hosting { + pub fn add_to_waitlist() {} + + pub fn seat_at_table() -> String { + String::from("sit down please") + } + } + + pub mod serving { + pub fn take_order() {} + + pub fn serve_order() {} + + pub fn take_payment() {} + + // Poate nu vrei ca oaspeții să audă plângerile tale despre ei + // Așa că fă-le private + fn complain() {} + } +} + +pub fn eat_at_restaurant() -> String { + front_of_house::hosting::add_to_waitlist(); + + back_of_house::cook_order(); + + String::from("yummy yummy!") +} + +pub mod back_of_house { + pub fn fix_incorrect_order() { + cook_order(); + crate::front_of_house::serving::serve_order(); + } + + pub fn cook_order() {} +} +``` + +4. 🌟🌟🌟🌟 Te rog să separi modulele și codurile de mai sus în fișiere aflate în arborele de directoare de mai jos: +```shell +. +├── Cargo.toml +├── src +│   ├── back_of_house.rs +│   ├── front_of_house +│   │   ├── hosting.rs +│   │   ├── mod.rs +│   │   └── serving.rs +│   ├── lib.rs +│   └── main.rs +``` + +```rust,editable +// În src/lib.rs + +// IMPLEMENTEAZĂ... +``` + +```rust,editable +// În src/back_of_house.rs + +// IMPLEMENTEAZĂ... +``` + + +```rust,editable +// În src/front_of_house/mod.rs + +// IMPLEMENTEAZĂ... +``` + +```rust,editable +// În src/front_of_house/hosting.rs + +// IMPLEMENTEAZĂ... +``` + +```rust,editable +// În src/front_of_house/serving.rs + +// IMPLEMENTEAZĂ... +``` + +### Accesarea codului în cutia de bibliotecă din cutia binară +**Te rog să te asiguri că ai finalizat a patra exercițiu înainte de a face progrese suplimentare.** + +Ar trebui să ai structurile de mai jos și codurile corespunzătoare în ele când ajungi aici: +```shell +. +├── Cargo.toml +├── src +│   ├── back_of_house.rs +│   ├── front_of_house +│   │   ├── hosting.rs +│   │   ├── mod.rs +│   │   └── serving.rs +│   ├── lib.rs +│   └── main.rs +``` + +5. 🌟🌟🌟 Acum vom apela câteva funcții de bibliotecă din cutia binară. + +```rust,editable +// În src/main.rs + +// COMPLETEAZĂ spațiul liber și CORECTEAZĂ erorile +fn main() { + assert_eq!(__, "sit down please"); + assert_eq!(__,"yummy yummy!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/crate-module/use-pub.md b/ro-RO/src/crate-module/use-pub.md new file mode 100644 index 000000000..391eb8a76 --- /dev/null +++ b/ro-RO/src/crate-module/use-pub.md @@ -0,0 +1,69 @@ +# Folosire și publicare +1. 🌟 Putem aduce două tipuri cu același nume în același domeniu cu 'use', dar avem nevoie de cuvântul cheie 'as'. + +```rust,editable +use std::fmt::Result; +use std::io::Result; + +fn main() {} +``` + +2. 🌟🌟 Dacă folosim mai multe elemente definite în aceeași creație sau modul, atunci listarea fiecărui element pe linie proprie va ocupa prea mult spațiu vertical. + +```rust,editable + +// COMPLETEAZĂ spațiul liber în două moduri +// NU adăuga linii noi de cod +use std::collections::__; + +fn main() { + let _c1:HashMap<&str, i32> = HashMap::new(); + let mut c2 = BTreeMap::new(); + c2.insert(1, "a"); + let _c3: HashSet = HashSet::new(); +} +``` + +### Re-exportarea numelor cu 'pub use' +3. 🌟🌟🌟 În pachetul nostru creat recent, hello-package, adaugă ceva pentru a face codul de mai jos să funcționeze. +```rust,editable +fn main() { + assert_eq!(hello_package::hosting::seat_at_table(), "sit down please"); + assert_eq!(hello_package::eat_at_restaurant(),"yummy yummy!"); +} +``` + + +### Pub(in Crate) +Uneori dorim ca un element să fie public doar pentru o anumită creație. Pentru asta putem folosi sintaxa pub(in Crate). + +#### Exemplu +```rust,editable +pub mod a { + pub const I: i32 = 3; + + fn semisecret(x: i32) -> i32 { + use self::b::c::J; + x + J + } + + pub fn bar(z: i32) -> i32 { + semisecret(I) * z + } + pub fn foo(y: i32) -> i32 { + semisecret(I) + y + } + + mod b { + pub(in crate::a) mod c { + pub(in crate::a) const J: i32 = 4; + } + } +} +``` + +### Cod Complet +Codul complet al hello-package se află [aici](https://github.com/sunface/rust-by-practice/tree/master/practices/hello-package). + + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/elegant-code-base.md b/ro-RO/src/elegant-code-base.md new file mode 100644 index 000000000..3384ff752 --- /dev/null +++ b/ro-RO/src/elegant-code-base.md @@ -0,0 +1,48 @@ +# Small projects with Elegant code base +Following questions come up weekly in online Rust discussions: + +- I just finished reading The Book, what should I do next ? +- What projects would you recommend to a Rust beginner? +- Looking for small projects with an elegant code base +- Codes that is easy to read and learn + +The answers to these questions are always **Practice**: doing some exercises, and then reading some small and excellent Rust projects. + +This is precisely the goal of this book, so, collecting relative resourses and representing in _Rust By Practice_ seems not a bad idea. + +### 1. Ripgrep + +Answers for above questions usually came with [`ripgrep`](https://github.com/BurntSushi/ripgrep), though I don't think it is a **small** project, but yes, go for it if you are not afraid to delve deep a bit. + +### 2. Building a text editor +Tutorial [`https://www.flenker.blog/hecto/`](https://www.flenker.blog/hecto/) will lead you to build a text editor from scratch. + +### 3. Ncspot +[Ncspot](https://github.com/hrkfdn/ncspot), a terminal Spotify client. Small, simple, well organized and async, it's good for learning. + +### 4. Command Line Rust +[This project](https://github.com/kyclark/command-line-rust) is for the book `Command-Line Rust(O'Reily)`, it will show you how to write small CLIs (clones of `head`, `cat`, `ls`). + +### 5. pngme book +[This book](https://picklenerd.github.io/pngme_book/) will guide you to make a command line program that lets you hide secret messages in PNG files. The primary goal here is to get you writing code. The secondary goal is to get you reading documentation. + +### 6. Writing an OS in Rust + +[This blog series](https://os.phil-opp.com) creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding [Github repository](https://github.com/phil-opp/blog_os). + + +### 7. CodeCrafters.io: Build your own Git, Docker, SQLite, or Redis + +On [CodeCrafters](https://codecrafters.io/for/rust), you can recreate your favorite developer tools from scratch. It's a hands-on, minimally-guided approach to master Rust, while appreciating the internals and documentation of popular technology that we use every day. + +### 8. mini-redis +[mini-redis](https://github.com/tokio-rs/mini-redis) is an incomplete Redis client and server implementation using tokio, it has decent code base and detail explanations, very suitable for learning Rust and asynchronous programming. + +### 9. Writing Interpreters in Rust + +[This online book](https://github.com/rust-hosted-langs/book) will walk through the basics of interpreted language implementation in Rust with a focus on the challenges that are specific to using Rust. + +--- + + +**To be continued...** diff --git a/ro-RO/src/errors.md b/ro-RO/src/errors.md new file mode 100644 index 000000000..165d08c36 --- /dev/null +++ b/ro-RO/src/errors.md @@ -0,0 +1 @@ +# Errors diff --git a/ro-RO/src/fight-compiler/borrowing.md b/ro-RO/src/fight-compiler/borrowing.md new file mode 100644 index 000000000..a9306f5ea --- /dev/null +++ b/ro-RO/src/fight-compiler/borrowing.md @@ -0,0 +1,30 @@ +# Împrumut (Borrowing) + +1. 🌟🌟 +```rust,editable +// REZOLVĂ eroarea fără a elimina nicio linie de cod: +struct test { + list: Vec, + a: i32 +} + +impl test { + pub fn new() -> Self { + test { list:vec![1,2,3,4,5,6,7], a:0 } + } + + pub fn run(&mut self) { + for i in self.list.iter() { + self.do_something(*i) + } + + } + + pub fn do_something(&mut self, n: i32) { + self.a = n; + } +} + +fn main() {} +``` +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/fight-compiler/intro.md b/ro-RO/src/fight-compiler/intro.md new file mode 100644 index 000000000..f414cbab3 --- /dev/null +++ b/ro-RO/src/fight-compiler/intro.md @@ -0,0 +1,4 @@ +# Lupta cu Compilatorul +Lupta cu compilatorul este foarte obișnuită în programarea noastră zilnică, în special pentru cei care nu sunt familiarizați cu limbajul Rust. + +Acest capitol va oferi câteva exerciții pentru a ne ajuta să evităm astfel de situații și să reducem curbura de învățare abruptă. \ No newline at end of file diff --git a/ro-RO/src/flow-control.md b/ro-RO/src/flow-control.md new file mode 100644 index 000000000..a24961007 --- /dev/null +++ b/ro-RO/src/flow-control.md @@ -0,0 +1,259 @@ +# Flow control + +### If/else +1. 🌟 +```rust,editable + +// Fill in the blanks +fn main() { + let n = 5; + + if n < 0 { + println!("{} is negative", n); + } __ n > 0 { + println!("{} is positive", n); + } __ { + println!("{} is zero", n); + } +} +``` + +2. 🌟🌟 `If/else` expression can be used in assignments. +```rust,editable + +// Fix the errors +fn main() { + let n = 5; + + let big_n = + if n < 10 && n > -10 { + println!(", and is a small number, increase ten-fold"); + + 10 * n + } else { + println!(", and is a big number, halve the number"); + + n / 2.0 ; + } + + println!("{} -> {}", n, big_n); +} +``` + +### For +3. 🌟 The `for in` construct can be used to iterate through an Iterator, e.g a range `a..b`. + +```rust,editable + +fn main() { + for n in 1..=100 { // modify this line to make the code work + if n == 100 { + panic!("NEVER LET THIS RUN") + } + } + + println!("Success!"); +} +``` + + +4. 🌟🌟 +```rust,editable + +// Fix the errors without adding or removing lines +fn main() { + let names = [String::from("liming"),String::from("hanmeimei")]; + for name in names { + // Do something with name... + } + + println!("{:?}", names); + + let numbers = [1, 2, 3]; + // The elements in numbers are Copy,so there is no move here + for n in numbers { + // Do something with n... + } + + println!("{:?}", numbers); +} +``` + +5. 🌟 +```rust,editable +fn main() { + let a = [4, 3, 2, 1]; + + // Iterate the indexing and value in 'a' + for (i,v) in a.__ { + println!("The {}th element is {}",i+1,v); + } +} +``` + +### While +6. 🌟🌟 The `while` keyword can be used to run a loop when a condition is true. + +```rust,editable + +// Fill in the blanks to make the last println! work ! +fn main() { + // A counter variable + let mut n = 1; + + // Loop while the condition is true + while n __ 10 { + if n % 15 == 0 { + println!("fizzbuzz"); + } else if n % 3 == 0 { + println!("fizz"); + } else if n % 5 == 0 { + println!("buzz"); + } else { + println!("{}", n); + } + + + __; + } + + println!("n reached {}, so loop is over",n); +} +``` + +### Continue and break +7. 🌟 Use `break` to break the loop. +```rust,editable + +// Fill in the blank +fn main() { + let mut n = 0; + for i in 0..=100 { + if n == 66 { + __ + } + n += 1; + } + + assert_eq!(n, 66); + + println!("Success!"); +} +``` + +8. 🌟🌟 `continue` will skip over the remaining code in current iteration and go to the next iteration. +```rust,editable + +// Fill in the blanks +fn main() { + let mut n = 0; + for i in 0..=100 { + if n != 66 { + n+=1; + __; + } + + __ + } + + assert_eq!(n, 66); + + println!("Success!"); +} +``` + +### Loop + +9. 🌟🌟 Loop is usually used together with `break` or `continue`. + +```rust,editable + +// Fill in the blanks +fn main() { + let mut count = 0u32; + + println!("Let's count until infinity!"); + + // Infinite loop + loop { + count += 1; + + if count == 3 { + println!("three"); + + // Skip the rest of this iteration + __; + } + + println!("{}", count); + + if count == 5 { + println!("OK, that's enough"); + + __; + } + } + + assert_eq!(count, 5); + + println!("Success!"); +} +``` + +10. 🌟🌟 Loop is an expression, so we can use it with `break` to return a value +```rust,editable + +// Fill in the blank +fn main() { + let mut counter = 0; + + let result = loop { + counter += 1; + + if counter == 10 { + __; + } + }; + + assert_eq!(result, 20); + + println!("Success!"); +} +``` + +11. 🌟🌟🌟 It's possible to break or continue outer loops when dealing with nested loops. In these cases, the loops must be annotated with some 'label, and the label must be passed to the break/continue statement. + +```rust,editable + +// Fill in the blank +fn main() { + let mut count = 0; + 'outer: loop { + 'inner1: loop { + if count >= 20 { + // This would break only the inner1 loop + break 'inner1; // `break` is also works. + } + count += 2; + } + + count += 5; + + 'inner2: loop { + if count >= 30 { + // This breaks the outer loop + break 'outer; + } + + // This will continue the outer loop + continue 'outer; + } + } + + assert!(count == __); + + println!("Success!"); +} +``` + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it \ No newline at end of file diff --git a/ro-RO/src/formatted-output/debug-display.md b/ro-RO/src/formatted-output/debug-display.md new file mode 100644 index 000000000..32e317d37 --- /dev/null +++ b/ro-RO/src/formatted-output/debug-display.md @@ -0,0 +1,156 @@ +# Debug și Display + +Toate tipurile care doresc să fie afișate trebuie să implementeze trăsătura de formatare `std::fmt`: `std::fmt::Debug` sau `std::fmt::Display`. + +Implementările automate sunt furnizate doar pentru tipuri precum cele din biblioteca `std`. Celelalte trebuie implementate manual. + +## Debug +Implementarea `Debug` este foarte simplă: Toate tipurile pot deriva implementarea `std::fmt::Debug`. Aceasta nu este valabilă pentru `std::fmt::Display`, care trebuie implementată manual. + +`{:?}` trebuie folosit pentru a afișa tipul care a implementat trăsătura `Debug`. + +```rust +// Această structură nu poate fi tipărită nici cu `fmt::Display` nici cu +// `fmt::Debug`. +struct UnPrintable(i32); + +// Pentru a face această structură imprimabilă cu `fmt::Debug`, putem deriva implementările automate furnizate de Rust +#[derive(Debug)] +struct DebugPrintable(i32); +``` + +1. 🌟 +```rust,editable + +/* Completați spațiile libere și remediați erorile */ +struct Structure(i32); + +fn main() { + // Tipurile din std și Rust au implementată trăsătura fmt::Debug + println!("__ months in a year.", 12); + + println!("Now __ will print!", Structure(3)); +} +``` + +2. 🌟🌟 Deci, fmt::Debug cu siguranță face un tip imprimabil, dar sacrifică puțină eleganță. Poate putem obține ceva mai elegant înlocuind {:?} cu altceva (dar nu și {}!) +```rust,editable +#[derive(Debug)] +struct Person { + name: String, + age: u8 +} + +fn main() { + let person = Person { name: "Sunface".to_string(), age: 18 }; + + /* Faceți să afișeze: + Person { + name: "Sunface", + age: 18, + } + */ + println!("{:?}", person); +} +``` + +3. 🌟🌟 Putem implementa și manual trăsătura Debug pentru tipurile noastre +```rust,editable + +#[derive(Debug)] +struct Structure(i32); + +#[derive(Debug)] +struct Deep(Structure); + + +fn main() { + // Problema cu `derive` este că nu există control asupra modului + // în care arată rezultatele. Ce se întâmplă dacă vreau să afișez doar un `7`? + + /* Faceți să afișeze: Acum 7 va fi tipărit! */ + println!("Now {:?} will print!", Deep(Structure(7))); +} +``` + +## Display +Da, Debug este simplu și ușor de folosit. Dar uneori vrem să personalizăm aspectul de ieșire al tipului nostru. Aici intervine Display. + +Spre deosebire de Debug, nu există nici o modalitate de a deriva implementarea trăsăturii Display, trebuie să o implementăm manual. + +Un alt lucru de remarcat: locul de substituire pentru Display este {}, nu {:?}. + +4. 🌟🌟 +```rust,editable + +/* Faceți să funcționeze*/ +use std::fmt; + +struct Point2D { + x: f64, + y: f64, +} + +impl fmt::Display for Point2D { + /* Implementați.. */ +} + +impl fmt::Debug for Point2D { + /* Implementați.. */ +} + +fn main() { + let point = Point2D { x: 3.3, y: 7.2 }; + assert_eq!(format!("{}",point), "Display: 3.3 + 7.2i"); + assert_eq!(format!("{:?}",point), "Debug: Complex { real: 3.3, imag: 7.2 }"); + + println!("Success!"); +} +``` + + +### Operatorul '?' + +Implementarea 'fmt::Display' pentru o structură a cărei elemente trebuie gestionate separat este dificilă. Problema este că fiecare 'write!' generează un 'fmt::Result' care trebuie gestionat în același loc. + +În mod fericit, Rust oferă operatorul '?' pentru a ne ajuta să eliminăm unele coduri inutile pentru tratarea rezultatului 'fmt::Result.' + +5. 🌟🌟 +```rust,editable + +/* Faceți să funcționeze */ +use std::fmt; + +struct List(Vec); + +impl fmt::Display for List { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Extrageți valoarea folosind indexarea tuplului, + // și creați o referință la `vec`. + let vec = &self.0; + + write!(f, "[")?; + + // Iterați peste `v` în `vec` în timp ce enumerați iterația + // numărul în `count`. + for (count, v) in vec.iter().enumerate() { + // Pentru fiecare element în afară de primul, adăugați o virgulă. + // Utilizați operatorul ? pentru a reveni la erori. + if count != 0 { write!(f, ", ")?; } + write!(f, "{}", v)?; + } + + // Închideți paranteza deschisă și returnați o valoare fmt::Result. + write!(f, "]") + } +} + +fn main() { + let v = List(vec![1, 2, 3]); + assert_eq!(format!("{}",v), "[0: 1, 1: 2, 2: 3]"); + println!("Success!"); +} +``` + + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/formatted-output/formatting.md b/ro-RO/src/formatted-output/formatting.md new file mode 100644 index 000000000..2832381f0 --- /dev/null +++ b/ro-RO/src/formatted-output/formatting.md @@ -0,0 +1,184 @@ +# Formatare + +## Argumente poziționale + +1.🌟🌟 +```rust,editable +/* Completați spațiile libere */ +fn main() { + println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob"); // => Alice, this is Bob. Bob, this is Alice + assert_eq!(format!("{1}{0}", 1, 2), __); + assert_eq!(format!(__, 1, 2), "2112"); + println!("Success!"); +} +``` + +## Argumente numite + +2.🌟🌟 +```rust,editable +fn main() { + println!("{argument}", argument = "test"); // => "test" + + /* Completați spațiile libere */ + assert_eq!(format!("{name}{}", 1, __), "21"); + assert_eq!(format!(__,a = "a", b = 'b', c = 3 ), "a 3 b"); + + /* Remediați eroarea */ + // Argumentul numit trebuie plasat după celelalte argumente + println!("{abc} {1}", abc = "def", 2); + + println!("Success!"); +} +``` + +## Umplerea cu spații a șirului (Padding cu string-uri) + +3.🌟🌟 În mod implicit, puteți umple șirul cu spații +```rust,editable +fn main() { + // Următoarele două umplu cu 5 spații + println!("Hello {:5}!", "x"); // => "Hello x !" + println!("Hello {:1$}!", "x", 5); // => "Hello x !" + + /* Completați spațiile libere */ + assert_eq!(format!("Hello __!", 5, "x"), "Hello x !"); + assert_eq!(format!("Hello __!", "x", width = 5), "Hello x !"); + + println!("Success!"); +} +``` + +4.🌟🌟🌟 Aliniere la stânga, dreapta, umplere cu caractere specificate. +```rust,editable +fn main() { + // Aliniere la stânga + println!("Hello {:<5}!", "x"); // => Hello x ! + // Aliniere la dreapta + assert_eq!(format!("Hello __!", "x"), "Hello x!"); + // Aliniere la centru + assert_eq!(format!("Hello __!", "x"), "Hello x !"); + + // Aliniere la stânga, umplere cu '&' + assert_eq!(format!("Hello {:&<5}!", "x"), __); + + println!("Success!"); +} +``` + +5.🌟🌟 Puteți umple numerele cu zerouri suplimentare. +```rust,editable +fn main() { + println!("Hello {:5}!", 5); // => Hello 5! + println!("Hello {:+}!", 5); // => Hello +5! + println!("Hello {:05}!", 5); // => Hello 00005! + println!("Hello {:05}!", -5); // => Hello -0005! + + /* Completați spațiile libere */ + assert!(format!("{number:0>width$}", number=1, width=6) == __); + + println!("Success!") +;} +``` + +## Precizie +6.🌟🌟 Precizie pentru virgulă mobilă +```rust,editable + +/* Completați spațiile libere */ +fn main() { + let v = 3.1415926; + + println!("{:.1$}", v, 4); // same as {:.4} => 3.1416 + + assert_eq!(format!("__", v), "3.14"); + assert_eq!(format!("__", v), "+3.14"); + assert_eq!(format!("__", v), "3"); + + println!("Success!"); +} +``` + +7.🌟🌟🌟 Lungimea șirului +```rust,editable +fn main() { + let s = "Hello, world!"; + + println!("{0:.5}", s); // => Hello + + assert_eq!(format!("Hello __!", 3, "abcdefg"), "Hello abc!"); + + println!("Success!"); +} +``` + +## Binare, octale, hexazecimale + +- format!("{}", foo) -> "3735928559" +- format!("0x{:X}", foo) -> "0xDEADBEEF" +- format!("0o{:o}", foo) -> "0o33653337357" + +8.🌟🌟 +```rust,editable +fn main() { + assert_eq!(format!("__", 27), "0b11011"); + assert_eq!(format!("__", 27), "0o33"); + assert_eq!(format!("__", 27), "0x1b"); + assert_eq!(format!("__", 27), "0x1B"); + + println!("{:x}!", 27); // Hex fără prefix => 1b + + println!("{:#010b}", 27); // Padding binar cu 0, lățime = 10, => 0b00011011 + + println!("Success!"); +} +``` + +## Capturarea mediului +9.🌟🌟🌟 +```rust,editable +fn get_person() -> String { + String::from("sunface") +} + +fn get_format() -> (usize, usize) { + (4, 1) +} + + +fn main() { + let person = get_person(); + println!("Hello, {person}!"); + + let (width, precision) = get_format(); + let scores = [("sunface", 99.12), ("jack", 60.34)]; + /* Faceți-l să afișeze: + sunface: 99.1 + jack: 60.3 + */ + for (name, score) in scores { + println!("{name}: __"); + } +} +``` + + +## Altele + +**Exemplu** +```rust,editable +fn main() { + // Exponent + println!("{:2e}", 1000000000); // => 1e9 + println!("{:2E}", 1000000000); // => 1E9 + + // Adresa pointerului + let v= vec![1, 2, 3]; + println!("{:p}", v.as_ptr()); // => 0x600002324050 + + // Escape + println!("Hello {{}}"); // => Hello {} +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/formatted-output/intro.md b/ro-RO/src/formatted-output/intro.md new file mode 100644 index 000000000..8b530e7d7 --- /dev/null +++ b/ro-RO/src/formatted-output/intro.md @@ -0,0 +1,63 @@ +# Formatarea ieșirilor + +```rust,editable,ignore,mdbook-runnable +fn main() { + // În general, `{}` va fi înlocuit automat cu orice argumente. + // Acestea vor fi transformate în șiruri de caractere. + println!("{} days", 31); + + // Fără un sufix, 31 devine un i32. Puteți schimba tipul lui 31 + // furnizând un sufix. Numărul 31i64, de exemplu, are tipul i64. + + // Există diverse modele opționale cu care acest lucru funcționează. + // Pot fi utilizate argumente poziționale. + println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob"); + + // La fel de bine pot fi folosite argumente denumite. + println!("{subject} {verb} {object}", + object="the lazy dog", + subject="the quick brown fox", + verb="jumps over"); + + // Se pot specifica formate speciale după un `:`. + println!("{} of {:b} people know binary, the other half doesn't", 1, 2); + + // Se poate alinia textul la dreapta cu o lățime specificată. + // Acesta va afișa " 1". 5 spații albe și un "1". + println!("{number:>width$}", number=1, width=6); + + // Se pot adăuga zerouri suplimentare la numere. + // Acesta va afișa "000001". + println!("{number:0>width$}", number=1, width=6); + + // Rust se asigură chiar și că se folosește numărul corect de argumente. + println!("My name is {0}, {1} {0}", "Bond"); + // FIXME ^ Adăugați argumentul lipsă: "James" + + // Creați o structură numită `Structure` care conține un `i32`. + #[allow(dead_code)] + struct Structure(i32); + + // Cu toate acestea, tipurile personalizate, cum ar fi această structură, necesită manipulări mai complicate. + // Acest lucru nu va funcționa. + println!("This struct `{}` won't print...", Structure(3)); + // FIXME ^ Comentați această linie. + + // Începând cu Rust 1.58 și mai sus, puteți captura direct argumentul din + // variabila înconjurătoare. La fel ca în exemplul de mai sus, acesta va afișa + // " 1". 5 spații albe și un "1". + let number: f64 = 1.0; + let width: usize = 6; + println!("{number:>width$}"); +} +``` + +[std::fmt][fmt] conține multe [traits][traits] care guvernează afișarea +textului. Forma de bază a două dintre cele mai importante este prezentată mai jos: + +* fmt::Debug: Utilizează marcajul {:?}. Formatează textul în scopuri de depanare. +* fmt::Display: Utilizează marcajul {}. Formatează textul într-un mod mai elegant și prietenos pentru utilizator. + +Aici, am folosit fmt::Display deoarece biblioteca standard oferă implementări pentru aceste tipuri. Pentru a tipări text pentru tipuri personalizate, sunt necesari mai mulți pași. + +Implementarea trait-ului fmt::Display implementează automat trait-ul [ToString], care ne permite să [convertim] tipul în [String][string]. diff --git a/ro-RO/src/formatted-output/println.md b/ro-RO/src/formatted-output/println.md new file mode 100644 index 000000000..a19a8b590 --- /dev/null +++ b/ro-RO/src/formatted-output/println.md @@ -0,0 +1,40 @@ +# 'println!' și 'format!' +Afișarea este gestionată de o serie de ['macro-uri'][macros] definite în ['std::fmt'][fmt], +Printre acestea se numără: + +* format!: scrie text formatat într-un [String][string] +* print!: la fel ca format!, dar textul este tipărit pe consolă (io::stdout). +* println!: la fel ca print!, dar se adaugă o linie nouă. +* eprint!: la fel ca format!, dar textul este tipărit pe eroarea standard (io::stderr). +* eprintln!: la fel ca eprint!, dar se adaugă o linie nouă. + +Toate parsează textul în același mod. În plus, Rust verifică corectitudinea formatului la momentul compilării. + +## `format!` +1.🌟 +```rust,editable + +fn main() { + let s1 = "hello"; + /* Completează spațiul liber */ + let s = format!(__); + assert_eq!(s, "hello, world!"); +} +``` + +## `print!`, `println!` +2.🌟 +```rust,editable + +fn main() { + /* Completați spațiile libere pentru a afișa: + Hello world, I am + Sunface! + */ + __("hello world, "); + __("I am"); + __("Sunface!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/functional-programing/closure.md b/ro-RO/src/functional-programing/closure.md new file mode 100644 index 000000000..0e6a3d204 --- /dev/null +++ b/ro-RO/src/functional-programing/closure.md @@ -0,0 +1,437 @@ +# Closure +Închideri (Closures) pot captura mediile înconjurate. De exemplu, putem captura variabila 'x': +```rust +fn main() { + let x = 1; + let closure = |val| val + x; + assert_eq!(closure(2), 3); +} +``` + +Din sintaxă, putem observa că închiderile sunt foarte convenabile pentru utilizarea pe loc. Spre deosebire de funcții, atât tipurile de intrare, cât și cele de ieșire ale unei închideri pot fi inferate de compilator. + +```rust +fn main() { + // Incrementare prin închideri și funcții. + fn function(i: i32) -> i32 { i + 1 } + + // Închiderile sunt anonime, aici le legăm la referințe + // + // Aceste funcții fără nume sunt atribuite unor variabile cu denumiri corespunzătoare. + let closure_annotated = |i: i32| -> i32 { i + 1 }; + let closure_inferred = |i | i + 1 ; + + let i = 1; + // Apelăm funcția și închiderile. + println!("function: {}", function(i)); + println!("closure_annotated: {}", closure_annotated(i)); + println!("closure_inferred: {}", closure_inferred(i)); + + // O închidere care nu primește argumente și returnează un `i32`. + // Tipul de returnare este inferat. + let one = || 1; + println!("closure returning one: {}", one()); + +} +``` + +## Capturarea +Închiderile pot captura variabile prin împrumut sau mutare. Dar ele preferă să captureze prin împrumut și să treacă la mutare doar când este necesar: + +- Prin referință: '&T' +- Prin referință mutabilă: '&mut T' +- Prin valoare: 'T' + + +1. 🌟 + +```rust,editable +/* Faceți să funcționeze cu cel mai mic număr de modificări posibile */ +fn main() { + let color = String::from("green"); + + let print = move || println!("`color`: {}", color); + + print(); + print(); + + // `color` poate fi împrumutat imutabil din nou, deoarece închiderea deține doar + // o referință imutabilă la `color`. + let _reborrow = &color; + + println!("{}",color); +} +``` + + +2. 🌟🌟 + +```rust,editable +/* Faceți să funcționeze +- Nu utilizați `_reborrow` și `_count_reborrowed` +- Nu modificați `assert_eq` +*/ +fn main() { + let mut count = 0; + + let mut inc = || { + count += 1; + println!("`count`: {}", count); + }; + + inc(); + + + let _reborrow = &count; + + inc(); + + // Închiderea nu mai are nevoie să împrumute `&mut count`. Prin urmare, este + // posibil să se facă un împrumut din nou fără eroare + let _count_reborrowed = &mut count; + + assert_eq!(count, 0); +} +``` + + +3. 🌟🌟 + +```rust,editable +/* Faceți să funcționeze în două moduri, niciunul dintre ele nu +este să eliminați `take(movable)` din cod */ +fn main() { + let movable = Box::new(3); + + let consume = || { + println!("`movable`: {:?}", movable); + take(movable); + }; + + consume(); + consume(); +} + +fn take(_v: T) {} +``` + +În comparație, următorul cod nu are eroare: +```rust +fn main() { + let movable = Box::new(3); + + let consume = move || { + println!("`movable`: {:?}", movable); + }; + + consume(); + consume(); +} +``` + +## Tipul inferat +Următoarele patru închideri nu au diferențe în tipurile de intrare și ieșire. + +```rust +fn add_one_v1 (x: u32) -> u32 { x + 1 } +let add_one_v2 = |x: u32| -> u32 { x + 1 }; +let add_one_v3 = |x| { x + 1 }; +let add_one_v4 = |x| x + 1 ; +``` + + +4. 🌟 + +```rust,editable +fn main() { + let example_closure = |x| x; + + let s = example_closure(String::from("hello")); + + /* Faceți să funcționeze, schimbând doar următoarea linie */ + let n = example_closure(5); +} +``` + +## Fn, FnMut, FnOnce +Atunci când se preia o închidere ca parametru de intrare, tipul complet al închiderii trebuie să fie adnotat folosind una dintre următoarele trăsături: + +- Fn: închiderea folosește valoarea capturată prin referință (&T) +- FnMut: închiderea folosește valoarea capturată prin referință mutabilă (&mut T) +- FnOnce: închiderea folosește valoarea capturată prin valoare (T) + + +5. 🌟🌟 + +```rust,editable +/* Faceți să funcționeze schimbând bound-ul trăsăturii, în două feluri*/ +fn fn_once(func: F) +where + F: FnOnce(usize) -> bool, +{ + println!("{}", func(3)); + println!("{}", func(4)); +} + +fn main() { + let x = vec![1, 2, 3]; + fn_once(|z|{z == x.len()}) +} +``` + +6. 🌟🌟 +```rust,editable +fn main() { + let mut s = String::new(); + + let update_string = |str| s.push_str(str); + + exec(update_string); + + println!("{:?}",s); +} + +/* Completați spațiile libere */ +fn exec<'a, F: __>(mut f: F) { + f("hello") +} +``` + +#### Pe care trăsătură preferă compilatorul să o folosească? +- Fn: închiderea folosește valoarea capturată prin referință (&T) +- FnMut: închiderea folosește valoarea capturată prin referință mutabilă (&mut T) +- FnOnce: închiderea folosește valoarea capturată prin valoare (T) + +În mod individual pentru fiecare variabilă, compilatorul va captura variabilele în cel mai puțin restrictiv mod posibil. + +De exemplu, să luăm în considerare un parametru notat ca FnOnce. Acest lucru specifică că închiderea poate captura prin '&T', '&mut T' sau 'T', dar compilatorul va alege în funcție de modul în care variabilele capturate sunt utilizate în închidere. +Trăsătura de utilizare este determinată de ceea ce face închiderea cu valorile capturate. + +Acest lucru se întâmplă pentru că dacă o mutare este posibilă, atunci orice tip de împrumut ar trebui să fie, de asemenea, posibil. Observați că inversul nu este adevărat. Dacă parametrul este notat ca Fn, atunci capturarea variabilelor prin '&mut T' sau 'T' nu este permisă. + + +7. 🌟🌟 + +```rust,editable +/* Completați spațiile libere */ + +// O funcție care primește o închidere ca argument și o apelează. +// indică faptul că F este un "Parametru de tip generic" +fn apply(f: F) where + // Închiderea nu primește niciun argument și nu returnează nimic. + F: __ { + + f(); +} + +// O funcție care primește o închidere și returnează un `i32`. +fn apply_to_3(f: F) -> i32 where + // Închiderea primește un `i32` și returnează un `i32`. + F: Fn(i32) -> i32 { + + f(3) +} + +fn main() { + use std::mem; + + let greeting = "hello"; + // Un tip care nu se copiază. + // `to_owned` creează date deținute din cele împrumutate + let mut farewell = "goodbye".to_owned(); + + // Capturăm 2 variabile: `greeting` prin referință și + // `farewell` prin valoare. + let diary = || { + // `greeting` este prin referință: necesită `Fn`. + println!("I said {}.", greeting); + + // Mutarea forțează `farewell` să fie capturat + // prin referință mutabilă. Acum necesită `FnMut`. + farewell.push_str("!!!"); + println!("Then I screamed {}.", farewell); + println!("Now I can sleep. zzzzz"); + + // Apelăm manual drop pentru a forța `farewell` să fie + // capturat prin valoare. Acum necesită `FnOnce`. + mem::drop(farewell); + }; + + // Apelăm funcția care aplică închiderea. + apply(diary); + + // `double` satisface condiția de trăsătură a lui `apply_to_3` + let double = |x| 2 * x; + + println!("3 doubled: {}", apply_to_3(double)); +} +``` + +Închiderile care mută pot implementa în continuare 'Fn' sau 'FnMut', chiar dacă capturează variabile prin mutare. Acest lucru se datorează faptului că trăsăturile implementate de un tip de închidere sunt determinate de ceea ce face închiderea cu valorile capturate, nu cum le capturează. Cuvântul cheie 'move' specifică doar ultimul aspect. + +```rust +fn main() { + let s = String::new(); + + let update_string = move || println!("{}",s); + + exec(update_string); +} + +fn exec(f: F) { + f() +} +``` + +Următorul cod nu are nicio eroare: +```rust +fn main() { + let s = String::new(); + + let update_string = move || println!("{}",s); + + exec(update_string); +} + +fn exec(f: F) { + f() +} +``` + + +8. 🌟🌟 + +```rust,editable +/* Completați spațiile libere */ +fn main() { + let mut s = String::new(); + + let update_string = |str| -> String {s.push_str(str); s }; + + exec(update_string); +} + +fn exec<'a, F: __>(mut f: F) { + f("hello"); +} +``` + + +## Funcții de intrare +Deoarece închiderile pot fi utilizate ca argumente, poate vă întrebați dacă putem utiliza și funcții ca argumente? Și cu siguranță că putem. + + +9. 🌟🌟 + +```rust,editable + +/* Implementați `call_me` pentru a funcționa */ +fn call_me { + f(); +} + +fn function() { + println!("I'm a function!"); +} + +fn main() { + let closure = || println!("I'm a closure!"); + + call_me(closure); + call_me(function); +} +``` + +## Închiderea ca tipuri de returnare +Returnarea unei închideri este mult mai dificilă decât ai fi crezut. + + +10. 🌟🌟 + +```rust,editable +/* Completați spațiul liber folosind două abordări, +și rezolvați eroarea */ +fn create_fn() -> __ { + let num = 5; + + // Cum capturează închiderea următoarea variabilă de mediu `num` + // &T, &mut T, T ? + |x| x + num +} + + +fn main() { + let fn_plain = create_fn(); + fn_plain(1); +} +``` + + +11. 🌟🌟 + +```rust,editable +/* Completați spațiul liber și rezolvați eroarea*/ +fn factory(x:i32) -> __ { + + let num = 5; + + if x > 1{ + move |x| x + num + } else { + move |x| x + num + } +} +``` + + +## Închideri în structuri + +**Exemplu** +```rust +struct Cacher +where + T: Fn(E) -> E, + E: Copy +{ + query: T, + value: Option, +} + +impl Cacher +where + T: Fn(E) -> E, + E: Copy +{ + fn new(query: T) -> Cacher { + Cacher { + query, + value: None, + } + } + + fn value(&mut self, arg: E) -> E { + match self.value { + Some(v) => v, + None => { + let v = (self.query)(arg); + self.value = Some(v); + v + } + } + } +} +fn main() { + +} + +#[test] +fn call_with_different_values() { + let mut c = Cacher::new(|a| a); + + let v1 = c.value(1); + let v2 = c.value(2); + + assert_eq!(v2, 1); +} +``` +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/functional-programing/intro.md b/ro-RO/src/functional-programing/intro.md new file mode 100644 index 000000000..d8b3c14f1 --- /dev/null +++ b/ro-RO/src/functional-programing/intro.md @@ -0,0 +1,5 @@ +# Programarea funcțională (Functional Programming) +Resurse de învățare: +- Engleză: [Rust Book 13](https://doc.rust-lang.org/book/ch13-00-functional-features.html) +- Chineză simplificată: [Rust语言圣经 - 函数式编程:闭包和迭代器](https://course.rs/advance/functional-programing/intro.html) + diff --git a/ro-RO/src/functional-programing/iterator.md b/ro-RO/src/functional-programing/iterator.md new file mode 100644 index 000000000..b8816c7f7 --- /dev/null +++ b/ro-RO/src/functional-programing/iterator.md @@ -0,0 +1,354 @@ +# Iterator +Modelul iterator permite efectuarea unor sarcini pe o secvență de elemente pe rând. Un iterator este responsabil pentru logica iterării prin fiecare element și determinarea momentului în care secvența s-a încheiat. + +## 'for' și iterator +```rust +fn main() { + let v = vec![1, 2, 3]; + for x in v { + println!("{}",x) + } +} +``` + +În codul de mai sus, puteți considera for ca un simplu ciclu, dar de fapt acesta iterează printr-un iterator. + +În mod implicit, 'for' va aplica 'into_iter' la colecție, transformând-o într-un iterator. Ca rezultat, codul de mai jos este echivalent cu cel anterior: +```rust +fn main() { + let v = vec![1, 2, 3]; + for x in v.into_iter() { + println!("{}",x) + } +} +``` + + +1. 🌟 + +```rust,editable +/* Refactorizați următorul cod folosind iteratori */ +fn main() { + let arr = [0; 10]; + for i in 0..arr.len() { + println!("{}",arr[i]); + } +} +``` + +2. 🌟 Una dintre cele mai simple modalități de a crea un iterator este utilizarea notației de interval: 'a..b'. +```rust,editable +/* Completați spațiul liber */ +fn main() { + let mut v = Vec::new(); + for n in __ { + v.push(n); + } + + assert_eq!(v.len(), 100); +} +``` + +## Metoda next +Toate iteratoarele implementează un trăsătura numită 'Iterator' definită în biblioteca standard: +```rust +pub trait Iterator { + type Item; + + fn next(&mut self) -> Option; + + // Metode cu implementări implicite eliberate +} +``` + +Și putem apela metoda 'next' direct pe iteratoare. + + +3. 🌟🌟 + +```rust,editable +/* Completați spațiile libere și rezolvați erorile. +Folosiți două modalități dacă este posibil */ +fn main() { + let v1 = vec![1, 2]; + + assert_eq!(v1.next(), __); + assert_eq!(v1.next(), __); + assert_eq!(v1.next(), __); +} +``` + +## 'into_iter', 'iter' și 'iter_mut' + +În secțiunea anterioară, am menționat că 'for' va aplica 'into_iter' la colecție și o va transforma într-un iterator. Cu toate acestea, aceasta nu este singura modalitate de a converti colecțiile în iteratoare. + +- 'into_iter', 'iter' și 'iter_mut', toate acestea pot converti o colecție într-un iterator, dar în moduri diferite. + +- 'into_iter' consumă colecția; o dată ce colecția a fost consumată, nu mai este disponibilă pentru reutilizare, deoarece stăpânirea sa a fost mutată în cadrul buclei. +- 'iter' împrumută fiecare element al colecției prin fiecare iterație, lăsând astfel colecția neatinsă și disponibilă pentru reutilizare după buclă. +- 'iter_mut' împrumută mutabil fiecare element al colecției, permițând modificarea colecției pe loc. + + +4. 🌟 + +```rust,editable +/* Faceți-l să funcționeze */ +fn main() { + let arr = vec![0; 10]; + for i in arr { + println!("{}", i); + } + + println!("{:?}",arr); +} +``` + + +5. 🌟 + +```rust,editable +/* Completați spațiul liber */ +fn main() { + let mut names = vec!["Bob", "Frank", "Ferris"]; + + for name in names.__{ + *name = match name { + &mut "Ferris" => "There is a rustacean among us!", + _ => "Hello", + } + } + + println!("names: {:?}", names); +} +``` + + +6. 🌟🌟 + +```rust,editable +/* Completați spațiul liber */ +fn main() { + let mut values = vec![1, 2, 3]; + let mut values_iter = values.__; + + if let Some(v) = values_iter.__{ + __ + } + + assert_eq!(values, vec![0, 2, 3]); +} +``` + + +## Crearea propriilor noștri iteratori +Nu putem doar crea iteratori din tipurile de colecție, ci și putem crea iteratori prin implementarea trăsăturii 'Iterator' pe propriile noastre tipuri. + +**Exemplu** +```rust +struct Counter { + count: u32, +} + +impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } +} + +impl Iterator for Counter { + type Item = u32; + + fn next(&mut self) -> Option { + if self.count < 5 { + self.count += 1; + Some(self.count) + } else { + None + } + } +} + +fn main() { + let mut counter = Counter::new(); + + assert_eq!(counter.next(), Some(1)); + assert_eq!(counter.next(), Some(2)); + assert_eq!(counter.next(), Some(3)); + assert_eq!(counter.next(), Some(4)); + assert_eq!(counter.next(), Some(5)); + assert_eq!(counter.next(), None); +} +``` + + +7. 🌟🌟🌟 + +```rust,editable +struct Fibonacci { + curr: u32, + next: u32, +} + +// Implementați `Iterator` pentru `Fibonacci`. +// Trăsătura `Iterator` necesită doar definirea unei metode pentru elementul `next`. +impl Iterator for Fibonacci { + // Putem să ne referim la acest tip folosind Self::Item + type Item = u32; + + /* Implementați metoda next */ + fn next(&mut self) +} + +// Returnează un generator de secvență Fibonacci +fn fibonacci() -> Fibonacci { + Fibonacci { curr: 0, next: 1 } +} + +fn main() { + let mut fib = fibonacci(); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(1)); + assert_eq!(fib.next(), Some(2)); + assert_eq!(fib.next(), Some(3)); + assert_eq!(fib.next(), Some(5)); +} +``` + +## Metode care consumă iteratorul +Trăsătura Iterator are un număr de metode cu implementări implicite furnizate de biblioteca standard. + +### Adaptoare de consum +Unele dintre aceste metode apelează metoda next pentru a utiliza iteratorul, astfel sunt numite adaptoare de consum. + + +8. 🌟🌟 + +```rust,edtiable + +/* Completați spațiul liber și rezolvați erorile */ +fn main() { + let v1 = vec![1, 2, 3]; + + let v1_iter = v1.iter(); + + // Metoda sum va lua stăpânirea iteratorului și va trece prin elemente apelând repetat metoda next + let total = v1_iter.sum(); + + assert_eq!(total, __); + + println!("{:?}, {:?}",v1, v1_iter); +} +``` + + +#### Colectare +În afară de conversia unei colecții într-un iterator, putem de asemenea să collectăm valorile rezultate într-o colecție, collect va consuma iteratorul. + + +9. 🌟🌟 + +```rust,editable +/* Faceți-l să funcționeze */ +use std::collections::HashMap; +fn main() { + let names = [("sunface",18), ("sunfei",18)]; + let folks: HashMap<_, _> = names.into_iter().collect(); + + println!("{:?}",folks); + + let v1: Vec = vec![1, 2, 3]; + + let v2 = v1.iter().collect(); + + assert_eq!(v2, vec![1, 2, 3]); +} +``` + + +### Adaptoare de iterator +Metodele care vă permit să schimbați un iterator în alt iterator sunt cunoscute sub numele de *adaptoare de iterator*. Puteți concatena mai multe adaptoare de iterator pentru a efectua acțiuni complexe într-un mod lizibil. + +Dar deoarece **toate iteratoarele sunt leneșe**, trebuie să apelați unul dintre adaptoarele de consum pentru a obține rezultate din apelurile la adaptoarele de iterator. + + +10. 🌟🌟 + +```rust,editable +/* Completați spațiile libere */ +fn main() { + let v1: Vec = vec![1, 2, 3]; + + let v2: Vec<_> = v1.iter().__.__; + + assert_eq!(v2, vec![2, 3, 4]); +} +``` + + +11. 🌟🌟 + +```rust +/* Completați spațiile libere */ +use std::collections::HashMap; +fn main() { + let names = ["sunface", "sunfei"]; + let ages = [18, 18]; + let folks: HashMap<_, _> = names.into_iter().__.collect(); + + println!("{:?}",folks); +} +``` + + +#### Utilizarea închiderilor în adaptoarele de iterator + + +12. 🌟🌟 + +```rust +/* Completați spațiile libere */ +#[derive(PartialEq, Debug)] +struct Shoe { + size: u32, + style: String, +} + +fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { + shoes.into_iter().__.collect() +} + +fn main() { + let shoes = vec![ + Shoe { + size: 10, + style: String::from("sneaker"), + }, + Shoe { + size: 13, + style: String::from("sandal"), + }, + Shoe { + size: 10, + style: String::from("boot"), + }, + ]; + + let in_my_size = shoes_in_size(shoes, 10); + + assert_eq!( + in_my_size, + vec![ + Shoe { + size: 10, + style: String::from("sneaker") + }, + Shoe { + size: 10, + style: String::from("boot") + }, + ] + ); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/generics-traits/advanced-traits.md b/ro-RO/src/generics-traits/advanced-traits.md new file mode 100644 index 000000000..2fb2bf4ca --- /dev/null +++ b/ro-RO/src/generics-traits/advanced-traits.md @@ -0,0 +1,279 @@ +# Trăsături Avansate + +## Tipuri asociate +Utilizarea "Tipurilor asociate" îmbunătățește în mod general citibilitatea codului prin mutarea tipurilor interne local într-o trăsătură ca tipuri de ieșire. De exemplu: +```rust +pub trait CacheableItem: Clone + Default + fmt::Debug + Decodable + Encodable { + type Address: AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash; + fn is_null(&self) -> bool; +} +``` + +Utilizarea tipului Adresa este mult mai clară și mai convenabilă decât 'AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash'. + +1. 🌟🌟🌟 +```rust,editable + +struct Container(i32, i32); + +// UTILIZAREA tipurilor asociate pentru a reimplementa trăsătura Contine. +// trăsătură Contine { +// tip A; +// tip B; + +trait Contains { + fn contains(&self, _: &A, _: &B) -> bool; + fn first(&self) -> i32; + fn last(&self) -> i32; +} + +impl Contains for Container { + fn contains(&self, number_1: &i32, number_2: &i32) -> bool { + (&self.0 == number_1) && (&self.1 == number_2) + } + // Preia primul număr. + fn first(&self) -> i32 { self.0 } + + // Preia ultimul număr. + fn last(&self) -> i32 { self.1 } +} + +fn difference>(container: &C) -> i32 { + container.last() - container.first() +} + +fn main() { + let number_1 = 3; + let number_2 = 10; + + let container = Container(number_1, number_2); + + println!("Does container contain {} and {}: {}", + &number_1, &number_2, + container.contains(&number_1, &number_2)); + println!("First number: {}", container.first()); + println!("Last number: {}", container.last()); + + println!("The difference is: {}", difference(&container)); +} +``` + +## Parametri de Tip Generic Implicit +Atunci când utilizăm parametri de tip generic, putem specifica un tip concret implicit pentru tipul generic. Acest lucru elimină necesitatea ca implementatorii trăsăturii să specifice un tip concret dacă tipul implicit funcționează. + +2. 🌟🌟 +```rust,editable + +use std::ops::Sub; + +#[derive(Debug, PartialEq)] +struct Point { + x: T, + y: T, +} + +// COMPLETAȚI spațiile libere în trei moduri: două dintre ele folosesc parametrii de tip generic implicit, cealaltă nu. +// Observați că implementarea folosește tipul asociat `Output`. +impl __ { + type Output = Self; + + fn sub(self, other: Self) -> Self::Output { + Point { + x: self.x - other.x, + y: self.y - other.y, + } + } +} + +fn main() { + assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 }, + Point { x: 1, y: 3 }); + + println!("Success!"); +} +``` + +## Sintaxă Complet Calificată +Nimic în Rust nu împiedică o trăsătură să aibă o metodă cu același nume ca o altă metodă a unei alte trăsături, iar Rust nu vă împiedică să implementați ambele trăsături pe un singur tip. De asemenea, este posibil să implementați o metodă direct pe tip cu același nume ca metodele din trăsături. + +Atunci când apelăm metode cu același nume, trebuie să folosim Sintaxa Complet Calificată. + +#### Exemplu +```rust,editable +trait UsernameWidget { + // Preia numele de utilizator selectat din acest widget + fn get(&self) -> String; +} + +trait AgeWidget { + // Preia vârsta selectată din acest widget + fn get(&self) -> u8; +} + +// O formă cu un WidgetNumeUtilizator(UsernameWidget), cât și un WidgetVârstă(AgeWidget). +struct Form { + username: String, + age: u8, +} + +impl UsernameWidget for Form { + fn get(&self) -> String { + self.username.clone() + } +} + +impl AgeWidget for Form { + fn get(&self) -> u8 { + self.age + } +} + +fn main() { + let form = Form{ + username: "rustacean".to_owned(), + age: 28, + }; + + // Dacă decomentați această linie, veți primi o eroare care spune + // "s-au găsit multiple `get`". Pentru că, în cele din urmă, există mai multe metode + // denumite `get`. + // println!("{}", form.get()); + + let username = UsernameWidget::get(&form); + assert_eq!("rustacean".to_owned(), username); + let age = AgeWidget::get(&form); // Puteți folosi și `
::get` + assert_eq!(28, age); + + println!("Success!"); +} +``` + +#### Exerciții +3. 🌟🌟 +```rust,editable +trait Pilot { + fn fly(&self) -> String; +} + +trait Wizard { + fn fly(&self) -> String; +} + +struct Human; + +impl Pilot for Human { + fn fly(&self) -> String { + String::from("This is your captain speaking.") + } +} + +impl Wizard for Human { + fn fly(&self) -> String { + String::from("Up!") + } +} + +impl Human { + fn fly(&self) -> String { + String::from("*waving arms furiously*") + } +} + +fn main() { + let person = Human; + + assert_eq!(__, "This is your captain speaking."); + assert_eq!(__, "Up!"); + + assert_eq!(__, "*waving arms furiously*"); + + println!("Success!"); +} +``` + +## Supertrăsături (Supertraits) +Uneori, s-ar putea să aveți nevoie ca o trăsătură să utilizeze funcționalitatea altei trăsături (ca "moștenirea" în alte limbaje). În acest caz, trebuie să vă bazați pe trăsătura dependentă pentru a fi implementată, fiind o 'supertrăsătură' a trăsăturii pe care o implementați. + +4. 🌟🌟🌟 +```rust,editable + +trait Person { + fn name(&self) -> String; +} + +// Persoană este o supertrăsătură a Studentului. +// Implementarea Studentului vă cere să implementați și Persoana. +trait Student: Person { + fn university(&self) -> String; +} + +trait Programmer { + fn fav_language(&self) -> String; +} + +// CompSciStudent (student de informatică) este o subtrăsătură a ambelor Programator +// și Student. Implementarea CompSciStudent vă cere să implementați ambele supertrăsături. +trait CompSciStudent: Programmer + Student { + fn git_username(&self) -> String; +} + +fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String { + format!( + "My name is {} and I attend {}. My favorite language is {}. My Git username is {}", + student.name(), + student.university(), + student.fav_language(), + student.git_username() + ) +} + +struct CSStudent { + name: String, + university: String, + fav_language: String, + git_username: String +} + +// IMPLEMENTAȚI trăsăturile necesare pentru StudCS pentru a face codul să funcționeze +impl ... + +fn main() { + let student = CSStudent { + name: "Sunfei".to_string(), + university: "XXX".to_string(), + fav_language: "Rust".to_string(), + git_username: "sunface".to_string() + }; + + // COMPLETAȚI spațiul liber + println!("{}", comp_sci_student_greeting(__)); +} +``` + +## Reguli Orfane +Nu putem implementa trăsături externe pe tipuri externe. De exemplu, nu putem implementa trăsătura 'Display' pentru 'Vec' în propria noastră create, deoarece 'Display' și 'Vec' sunt definite în biblioteca standard și nu sunt locale în cadrul createi noastre. + +Această restricție este adesea numită regula orfan, numită astfel deoarece tipul părinte nu este prezent. Această regulă asigură că codul altor persoane nu poate afecta codul vostru și invers. + +Este posibil să se ocolească această restricție folosind șablonul newtype, care implică crearea unui nou tip într-o structură de tupluri. + +5. 🌟🌟 +```rust,editable +use std::fmt; + +// DEFINIȚI un șablon newtype `Frumos` aici + + +impl fmt::Display for Pretty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"{}\"", self.0.clone() + ", world") + } +} + +fn main() { + let w = Pretty("hello".to_string()); + println!("w = {}", w); +} +``` + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it :) \ No newline at end of file diff --git a/ro-RO/src/generics-traits/const-generics.md b/ro-RO/src/generics-traits/const-generics.md new file mode 100644 index 000000000..0a223d44d --- /dev/null +++ b/ro-RO/src/generics-traits/const-generics.md @@ -0,0 +1,146 @@ +# Generice Constante +Genericele constante reprezintă argumente generice care variază asupra valorilor constante, în loc de tipuri sau durate de viață. Acest lucru permite, de exemplu, tipurilor să fie parametrizate de numere întregi. De fapt, există un exemplu de tipuri generice constante încă de la începutul dezvoltării limbajului Rust: tipurile de tablou [T; N], pentru un anumit tip T și N: usize. Cu toate acestea, nu a existat anterior o modalitate de a abstrage asupra tablourilor de dimensiune arbitrară: dacă doreați să implementați o trăsătură pentru tablouri de orice dimensiune, trebuia să faceți acest lucru manual pentru fiecare valoare posibilă. Timp îndelungat, chiar și metodele standard ale bibliotecii pentru tablouri au fost limitate la tablouri de lungime cel mult 32 din cauza acestei probleme. + +## Exemple +1. Iată un exemplu de tip și implementare care folosește generice constante: un tip care înconjoară o pereche de tablouri de aceeași dimensiune. +```rust,editable +struct ArrayPair { + left: [T; N], + right: [T; N], +} + +impl Debug for ArrayPair { + // ... +} +``` + + +2. În prezent, parametrii const pot fi instanțiați numai de argumente const ale formelor următoare: + +- Un parametru const separat. +- O literă (adică un întreg, bool sau caracter). +- O expresie constantă concretă (închisă între {}), care nu implică niciun parametru generic. + +```rust,editable +fn foo() {} + +fn bar() { + foo::(); // Corect: `M` este un parametru const + foo::<2021>(); // Corect: `2021` este o literă + foo::<{20 * 100 + 20 * 10 + 1}>(); // Corect: expresia const conține zero parametri generici + + foo::<{ M + 1 }>(); // Eroare: expresia const conține parametrul generic `M` + foo::<{ std::mem::size_of::() }>(); // Eroare: expresia const conține parametrul generic `T` + + + let _: [u8; M]; // Corect: `M` este un parametru const + let _: [u8; std::mem::size_of::()]; // Eroare: expresia const conține parametrul generic `T` +} + +fn main() {} +``` + +3. Genericele constante ne pot permite, de asemenea, să evităm unele verificări la timpul de execuție. +```rust +/// O regiune de memorie conținând cel puțin `N` elemente de tip `T`. +pub struct MinSlice { + /// Regiunea mărginită de memorie. Exact `N` elemente de tip `T`. + pub head: [T; N], + /// Zero sau mai multe elemente `T` rămase după cele `N` din regiunea mărginită. + pub tail: [T], +} + +fn main() { + let slice: &[u8] = b"Hello, world"; + let reference: Option<&u8> = slice.get(6); + // Știm că această valoare este `Some(b' ')`, + // dar compilatorul nu poate ști asta. + assert!(reference.is_some()); + + let slice: &[u8] = b"Hello, world"; + // Verificarea lungimii este efectuată când construim un MinSlice, + // și se știe la timpul de compilare că are lungimea 12. + // Dacă `unwrap()` reușește, nu mai sunt necesare verificări + // pe durata vieții `MinSlice`. + let minslice = MinSlice::::from_slice(slice).unwrap(); + let value: u8 = minslice.head[6]; + assert_eq!(value, b' ') +} +``` + + +## Exerciții +1. 🌟🌟 '' face parte din tipul structurii, ceea ce înseamnă că 'Array' și 'Array' sunt tipuri diferite. + +```rust,editable +struct Array { + data : [T; N] +} + +fn main() { + let arrays = [ + Array{ + data: [1, 2, 3], + }, + Array { + data: [1.0, 2.0, 3.0], + }, + Array { + data: [1, 2] + } + ]; + + println!("Success!"); +} +``` + +2. 🌟🌟 +```rust,editable + +// Completați spațiile libere pentru a face codul funcțional. +fn print_array<__>(__) { + println!("{:?}", arr); +} +fn main() { + let arr = [1, 2, 3]; + print_array(arr); + + let arr = ["hello", "world"]; + print_array(arr); +} +``` + +3. 🌟🌟🌟 Uneori vrem să limităm dimensiunea unei variabile, de exemplu, când o folosim în medii integrate, apoi 'const expressions' vor fi soluția potrivită. + +```rust,editable +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +fn check_size(val: T) +where + Assert<{ core::mem::size_of::() < 768 }>: IsTrue, +{ + //... +} + +// Rezolvați erorile din funcția principală. +fn main() { + check_size([0u8; 767]); + check_size([0i32; 191]); + check_size(["hello你好"; __]); // Dimensiunea &str? + check_size([(); __].map(|_| "hello你好".to_string())); // Dimensiunea String? + check_size(['中'; __]); // Dimensiunea char ? + + println!("Success!"); +} + + + +pub enum Assert {} + +pub trait IsTrue {} + +impl IsTrue for Assert {} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/generics-traits/generics.md b/ro-RO/src/generics-traits/generics.md new file mode 100644 index 000000000..c74aa3ff1 --- /dev/null +++ b/ro-RO/src/generics-traits/generics.md @@ -0,0 +1,155 @@ +# Generice + +### Funcții +1. 🌟🌟🌟 +```rust,editable + +// Completați spațiile libere pentru a face codul să funcționeze +struct A; // Tip concret `A`. +struct S(A); // Tip concret `S`. +struct SGen(T); // Tip generic `SGen`. + +fn reg_fn(_s: S) {} + +fn gen_spec_t(_s: SGen) {} + +fn gen_spec_i32(_s: SGen) {} + +fn generic(_s: SGen) {} + +fn main() { + // Folosind funcțiile non-generice + reg_fn(__); // Tip concret. + gen_spec_t(__); // Parametru de tip `A` specificat implicit. + gen_spec_i32(__); // Parametru de tip `i32` specificat implicit. + + // Parametru de tip `char` specificat explicit pentru `generic()`. + generic::(__); + + // Parametru de tip `char` specificat implicit pentru `generic()`. + generic(__); + + println!("Success!"); +} +``` + +2. 🌟🌟 Un apel de funcție cu parametri de tip specificați explicit arată astfel: 'fun::()'. +```rust,editable + +// Implementați funcția generică mai jos. +fn sum + +fn main() { + assert_eq!(5, sum(2i8, 3i8)); + assert_eq!(50, sum(20, 30)); + assert_eq!(2.46, sum(1.23, 1.23)); + + println!("Success!"); +} +``` + + +### Structură și impl + +3. 🌟 +```rust,editable + +// Implementați structura Punct pentru a face codul să funcționeze. + + +fn main() { + let integer = Point { x: 5, y: 10 }; + let float = Point { x: 1.0, y: 4.0 }; + + println!("Success!"); +} +``` + +4. 🌟🌟 +```rust,editable + +// Modificați această structură pentru a face codul să funcționeze +struct Point { + x: T, + y: T, +} + +fn main() { + // NU modificați acest cod. + let p = Point{x: 5, y : "hello".to_string()}; + + println!("Success!"); +} +``` + +5. 🌟🌟 +```rust,editable + +// Adăugați generic pentru Val pentru a face codul să funcționeze, NU modificați codul din `main`. +struct Val { + val: f64, +} + +impl Val { + fn value(&self) -> &f64 { + &self.val + } +} + + +fn main() { + let x = Val{ val: 3.0 }; + let y = Val{ val: "hello".to_string()}; + println!("{}, {}", x.value(), y.value()); +} +``` + +### Metodă +6. 🌟🌟🌟 + +```rust,editable +struct Point { + x: T, + y: U, +} + +impl Point { + // Implementați mixup pentru a face codul să funcționeze, NU modificați alte coduri. + fn mixup +} + +fn main() { + let p1 = Point { x: 5, y: 10 }; + let p2 = Point { x: "Hello", y: '中'}; + + let p3 = p1.mixup(p2); + + assert_eq!(p3.x, 5); + assert_eq!(p3.y, '中'); + + println!("Success!"); +} +``` + +7. 🌟🌟 +```rust,editable + +// Corectați erorile pentru a face codul să funcționeze. +struct Point { + x: T, + y: T, +} + +impl Point { + fn distance_from_origin(&self) -> f32 { + (self.x.powi(2) + self.y.powi(2)).sqrt() + } +} + +fn main() { + let p = Point{x: 5, y: 10}; + println!("{}",p.distance_from_origin()); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/generics-traits/intro.md b/ro-RO/src/generics-traits/intro.md new file mode 100644 index 000000000..e1b5b7978 --- /dev/null +++ b/ro-RO/src/generics-traits/intro.md @@ -0,0 +1,6 @@ +# Generice și Trăsături (Traits) +Resurse de învățare: +- Engleză: [Rust Book 10.1, 10.2](https://doc.rust-lang.org/book/ch10-00-generics.html) +- Chineză simplificată: [Rust语言圣经 - 模式匹配](https://course.rs/basic/trait/intro.html) + + diff --git a/ro-RO/src/generics-traits/trait-object.md b/ro-RO/src/generics-traits/trait-object.md new file mode 100644 index 000000000..c134239e2 --- /dev/null +++ b/ro-RO/src/generics-traits/trait-object.md @@ -0,0 +1,229 @@ +# Obiecte de Trăsături (Trait Object) +În [capitolul despre trăsături](https://practice.rs/generics-traits/traits.html#returning-types-that-implement-traits) am văzut că nu putem folosi impl Trait atunci când returnăm mai multe tipuri. + +O altă limitare a array-urilor este că pot stoca doar elemente de un singur tip. Utilizarea enum-urilor nu este o soluție rea atunci când avem un set fix de tipuri la timpul de compilare, dar obiectele de trăsături ar fi mai flexibile și mai puternice. + +## Returnarea Trăsăturilor cu 'dyn' +Compilatorul Rust trebuie să știe cât spațiu necesită tipul de returnare al unei funcții. Deoarece implementările diferite ale unei trăsături folosesc probabil cantități diferite de memorie, funcțiile trebuie să returneze fie un tip concret sau același tip atunci când se folosește 'impl Trait', fie să returneze un obiect de trăsătură cu 'dyn'. + +1. 🌟🌟🌟 +```rust,editable + +trait Bird { + fn quack(&self) -> String; +} + +struct Duck; +impl Duck { + fn swim(&self) { + println!("Look, the duck is swimming") + } +} +struct Swan; +impl Swan { + fn fly(&self) { + println!("Look, the duck.. oh sorry, the swan is flying") + } +} + +impl Bird for Duck { + fn quack(&self) -> String{ + "duck duck".to_string() + } +} + +impl Bird for Swan { + fn quack(&self) -> String{ + "swan swan".to_string() + } +} + +fn main() { + // Completați spațiul liber. + let duck = __; + duck.swim(); + + let bird = hatch_a_bird(2); + // Această pasăre a uitat să înoate, așa că linia de mai jos va provoca o eroare. + // pasare.inoata(); + // Dar poate cotcodă. + assert_eq!(bird.quack(), "duck duck"); + + let bird = hatch_a_bird(1); + // Această pasăre a uitat să zboare, așa că linia de mai jos va provoca o eroare. + // pasare.zboară(); + // Dar poate cotcodă și ea. + assert_eq!(bird.quack(), "swan swan"); + + println!("Success!"); +} + +// IMPLEMENTAȚI această funcție. +fn hatch_a_bird... + +``` +## Array cu obiecte de trăsături +2. 🌟🌟 +```rust,editable +trait Bird { + fn quack(&self); +} + +struct Duck; +impl Duck { + fn fly(&self) { + println!("Look, the duck is flying") + } +} +struct Swan; +impl Swan { + fn fly(&self) { + println!("Look, the duck.. oh sorry, the swan is flying") + } +} + +impl Bird for Duck { + fn quack(&self) { + println!("{}", "duck duck"); + } +} + +impl Bird for Swan { + fn quack(&self) { + println!("{}", "swan swan"); + } +} + +fn main() { + // Completați spațiul liber pentru a face codul să funcționeze. + let birds __; + + for bird in birds { + bird.quack(); + // Când rata și lebăda se transformă în Păsări, ele au uitat cum să zboare, au reținut doar cum să cotcodească. + // Așadar, codul de mai jos va provoca o eroare. + // bird.fly(); + } +} +``` + + +## `&dyn' și 'Box' + +3. 🌟🌟 +```rust,editable + +// Completați spațiile libere. +trait Draw { + fn draw(&self) -> String; +} + +impl Draw for u8 { + fn draw(&self) -> String { + format!("u8: {}", *self) + } +} + +impl Draw for f64 { + fn draw(&self) -> String { + format!("f64: {}", *self) + } +} + +fn main() { + let x = 1.1f64; + let y = 8u8; + + // Desenează x. + draw_with_box(__); + + // Desenează y. + draw_with_ref(&y); + + println!("Success!"); +} + +fn draw_with_box(x: Box) { + x.draw(); +} + +fn draw_with_ref(x: __) { + x.draw(); +} +``` + +## Dispatch Static și Dinamic +Când folosim limite de trăsături pe generice, compilatorul generează implementări nongenerice ale funcțiilor și metodelor pentru fiecare tip concret pe care îl folosim în locul unui parametru generic de tip. Codul rezultat din monomorfizare realizează un dispatch static, adică când compilatorul știe ce metodă apelezi în timpul compilării. + +Când folosim obiecte de trăsături, Rust trebuie să folosească un dispatch dinamic. Compilatorul nu cunoaște toate tipurile care ar putea fi folosite cu codul care utilizează obiecte de trăsături, așa că nu știe ce metodă implementată pe ce tip să apeleze. În schimb, la runtime, Rust folosește pointerii din obiectul de trăsătură pentru a ști ce metodă să apeleze. Există un cost la runtime atunci când se face această căutare, care nu apare în cazul dispatch-ului static. Dispatch-ul dinamic împiedică, de asemenea, compilatorul să aleagă să încorporeze codul unei metode, ceea ce, la rândul său, împiedică unele optimizări. + +Cu toate acestea, obținem flexibilitate suplimentară atunci când folosim dispatch-ul dinamic. + +4. 🌟🌟 +```rust,editable + +trait Foo { + fn method(&self) -> String; +} + +impl Foo for u8 { + fn method(&self) -> String { format!("u8: {}", *self) } +} + +impl Foo for String { + fn method(&self) -> String { format!("string: {}", *self) } +} + +// IMPLEMENTAȚI mai jos cu generice. +fn static_dispatch... + +// Implementați mai jos cu obiecte de trăsături. +fn dynamic_dispatch... + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + static_dispatch(x); + dynamic_dispatch(&y); + + println!("Success!"); +} +``` + +## Obiect sigur +Puteți face doar din trăsături care sunt sigure pentru obiecte trăsătură. O trăsătură este sigură pentru obiect dacă toate metodele definite în trăsătură au următoarele proprietăți: + +- Tipul de returnare nu este Self. +- Nu există parametri de tip generic. + +5. 🌟🌟🌟🌟 +```rust,editable + +// Folosiți cel puțin două abordări pentru a face codul să funcționeze. +// NU adăugați/eliminați nici o linie de cod. +trait MyTrait { + fn f(&self) -> Self; +} + +impl MyTrait for u32 { + fn f(&self) -> Self { 42 } +} + +impl MyTrait for String { + fn f(&self) -> Self { self.clone() } +} + +fn my_function(x: Box) { + x.f() +} + +fn main() { + my_function(Box::new(13_u32)); + my_function(Box::new(String::from("abc"))); + + println!("Success!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/generics-traits/traits.md b/ro-RO/src/generics-traits/traits.md new file mode 100644 index 000000000..0d2cb55c8 --- /dev/null +++ b/ro-RO/src/generics-traits/traits.md @@ -0,0 +1,471 @@ +# Trăsături +O trăsătură spune compilatorului Rust despre funcționalitatea pe care un anumit tip o are și pe care o poate împărtăși cu alte tipuri. Putem folosi trăsături pentru a defini comportament comun într-un mod abstract. Putem utiliza constrângeri de trăsături pentru a specifica că un tip generic poate fi orice tip care are anumit comportament. + +> Notă: Trăsăturile sunt similare cu interfețele în alte limbaje, deși există unele diferențe. + +## Exemple +```rust,editable + +struct Sheep { naked: bool, name: String } + +trait Animal { + // Semnătura funcției asociate; `Self` se referă la tipul implementatorului. + fn new(name: String) -> Self; + + // Semnăturile metodei; acestea vor returna un șir de caractere. + fn name(&self) -> String; + + fn noise(&self) -> String; + + // Trăsăturile pot oferi definiții implicite pentru metode. + fn talk(&self) { + println!("{} says {}", self.name(), self.noise()); + } +} + +impl Sheep { + fn is_naked(&self) -> bool { + self.naked + } + + fn shear(&mut self) { + if self.is_naked() { + // Metodele implementatorului pot folosi metodele trăsăturii ale implementatorului. + println!("{} is already naked...", self.name()); + } else { + println!("{} gets a haircut!", self.name); + + self.naked = true; + } + } +} + +// Implementați trăsătura `Animal` pentru `Sheep`. +impl Animal for Sheep { + // `Self` este tipul implementator: `Sheep`. + fn new(name: String) -> Sheep { + Sheep { name: name, naked: false } + } + + fn name(&self) -> String { + self.name.clone() + } + + fn noise(&self) -> String { + if self.is_naked() { + "baaaaah?".to_string() + } else { + "baaaaah!".to_string() + } + } + + // Metodele implicite ale trăsăturii pot fi suprascrise. + fn talk(&self) { + // De exemplu, putem adăuga o contemplare scurtă. + println!("{} pauses briefly... {}", self.name, self.noise()); + } +} + +fn main() { + // Este necesară anotarea tipului în acest caz. + let mut dolly: Sheep = Animal::new("Dolly".to_string()); + // TODO ^ Încercați să eliminați anotările de tip. + + dolly.talk(); + dolly.shear(); + dolly.talk(); +} +``` + +## Exercises +1. 🌟🌟 +```rust,editable + +// Completați cele două blocuri `impl` pentru a face codul să funcționeze. +// NU modificați codul din `main`. +trait Hello { + fn say_hi(&self) -> String { + String::from("hi") + } + + fn say_something(&self) -> String; +} + +struct Student {} +impl Hello for Student { +} +struct Teacher {} +impl Hello for Teacher { +} + +fn main() { + let s = Student {}; + assert_eq!(s.say_hi(), "hi"); + assert_eq!(s.say_something(), "I'm a good student"); + + let t = Teacher {}; + assert_eq!(t.say_hi(), "Hi, I'm your new teacher"); + assert_eq!(t.say_something(), "I'm not a bad teacher"); + + println!("Success!"); +} +``` + +### Derivare +Compilatorul este capabil să furnizeze implementări de bază pentru unele trăsături prin intermediul atributului `#[derive]`. Pentru mai multe informații, vă rugăm să vizitați [aici](https://doc.rust-lang.org/book/appendix-03-derivable-traits.html). + +2. 🌟🌟 +```rust,editable + +// `Centimeters`, o structură tuplu care poate fi comparată +#[derive(PartialEq, PartialOrd)] +struct Centimeters(f64); + +// `Inches`, o structură tuplu care poate fi afișată +#[derive(Debug)] +struct Inches(i32); + +impl Inches { + fn to_centimeters(&self) -> Centimeters { + let &Inches(inches) = self; + + Centimeters(inches as f64 * 2.54) + } +} + +// ADAUGAȚI unele atribute pentru a face codul să funcționeze! +// NU modificați alt cod! +struct Seconds(i32); + +fn main() { + let _one_second = Seconds(1); + + println!("One second looks like: {:?}", _one_second); + let _this_is_true = (_one_second == _one_second); + let _this_is_false = (_one_second > _one_second); + + let foot = Inches(12); + + println!("One foot equals {:?}", foot); + + let meter = Centimeters(100.0); + + let cmp = + if foot.to_centimeters() < meter { + "smaller" + } else { + "bigger" + }; + + println!("One foot is {} than one meter.", cmp); +} +``` + + +### Operator +În Rust, mulți dintre operatori pot fi suprascriși prin intermediul trăsăturilor. Adică, unele operații pot fi utilizate pentru a realiza diferite sarcini în funcție de argumentele lor de intrare. Acest lucru este posibil pentru că operatorii sunt zahăr sintactic pentru apeluri de metode. De exemplu, operatorul '+' în a + b apelează metoda 'add' (ca în a.add(b)). Această metodă 'add' face parte din trăsătura 'Add'. Prin urmare, operatorul '+' poate fi folosit de orice implementator al trăsăturii 'Add'. + +3. 🌟🌟 +```rust,editable + +use std::ops; + +// Implementați funcția `înmulți` pentru a face codul să funcționeze. +// Așa cum s-a menționat mai sus, `+` are nevoie de `T` să implementeze trăsătura `std::ops::Add`. +// Deci, ce se întâmplă cu `*`? Puteți găsi răspunsul aici: https://doc.rust-lang.org/core/ops/ +fn multipl + +fn main() { + assert_eq!(6, multiply(2u8, 3u8)); + assert_eq!(5.0, multiply(1.0, 5.0)); + + println!("Success!"); +} +``` + +4. 🌟🌟🌟 +```rust,editable + +// Remediați erorile, NU modificați codul din `main`. +use std::ops; + +struct Foo; +struct Bar; + +struct FooBar; + +struct BarFoo; + +// Trăsătura `std::ops::Add` este utilizată pentru a specifica funcționalitatea `+`. +// Aici, facem `Add` - trăsătura pentru adunare cu un RHS de tip `Bar`. +// Blocul următor implementează operația: Foo + Bar = FooBar +impl ops::Add for Foo { + type Output = FooBar; + + fn add(self, _rhs: Bar) -> FooBar { + FooBar + } +} + +impl ops::Sub for Bar { + type Output = BarFoo; + + fn sub(self, _rhs: Foo) -> BarFoo { + BarFoo + } +} + +fn main() { + // NU modificați codul de mai jos. + // Trebuie să derivați unele trăsături pentru FooBar pentru a le face comparabile. + assert_eq!(Foo + Bar, FooBar); + assert_eq!(Foo - Bar, BarFoo); + + println!("Success!"); +} +``` + +### Folosirea trăsăturii ca parametru pentru funcții +În loc de un tip concret pentru parametrul elementului, specificăm cuvântul cheie impl și numele trăsăturii. Acest parametru acceptă orice tip care implementează trăsătura specificată. + +5. 🌟🌟🌟 +```rust,editable + +// Implementați `fn rezumat` pentru a face codul să funcționeze. +// Remediați erorile fără a elimina nicio linie de cod +trait Summary { + fn summarize(&self) -> String; +} + +#[derive(Debug)] +struct Post { + title: String, + author: String, + content: String, +} + +impl Summary for Post { + fn summarize(&self) -> String { + format!("The author of post {} is {}", self.title, self.author) + } +} + +#[derive(Debug)] +struct Weibo { + username: String, + content: String, +} + +impl Summary for Weibo { + fn summarize(&self) -> String { + format!("{} published a weibo {}", self.username, self.content) + } +} + +fn main() { + let post = Post { + title: "Popular Rust".to_string(), + author: "Sunface".to_string(), + content: "Rust is awesome!".to_string(), + }; + let weibo = Weibo { + username: "sunface".to_string(), + content: "Weibo seems to be worse than Tweet".to_string(), + }; + + summary(post); + summary(weibo); + + println!("{:?}", post); + println!("{:?}", weibo); +} + +// Implementați `fn summary` mai jos. + +``` + +### Returnarea tipurilor care implementează trăsături +Putem folosi, de asemenea, sintaxa 'impl Trait' în poziția de returnare pentru a returna o valoare de un anumit tip care implementează o trăsătură. + +Cu toate acestea, puteți utiliza 'impl Trait' doar atunci când returnați un singur tip, folosiți Obiectele Trăsăturii atunci când aveți nevoie cu adevărat să returnați mai multe tipuri. + +6. 🌟🌟 +```rust,editable + +struct Sheep {} +struct Cow {} + +trait Animal { + fn noise(&self) -> String; +} + +impl Animal for Sheep { + fn noise(&self) -> String { + "baaaaah!".to_string() + } +} + +impl Animal for Cow { + fn noise(&self) -> String { + "moooooo!".to_string() + } +} + +/ Returnează unele structuri care implementează Animal, dar nu știm care la momentul compilării. +// REMEDIAȚI erorile aici, puteți face o glumă aleatoare, sau puteți utiliza un obiect de trăsătură. +fn random_animal(random_number: f64) -> impl Animal { + if random_number < 0.5 { + Sheep {} + } else { + Cow {} + } +} + +fn main() { + let random_number = 0.234; + let animal = random_animal(random_number); + println!("You've randomly chosen an animal, and it says {}", animal.noise()); +} +``` + +### Condiție de trăsătură +Sintaxa 'impl Trait' funcționează pentru cazurile simple, dar este de fapt zahăr sintactic pentru o formă mai lungă, numită condiție de trăsătură. + +Atunci când lucrați cu generice, parametrii de tip trebuie să utilizeze adesea trăsături ca limite pentru a specifica funcționalitatea pe care un tip o implementează. + +7. 🌟🌟 +```rust,editable +fn main() { + assert_eq!(sum(1, 2), 3); +} + +// Implementați `fn sum` cu condiție de trăsătură în două moduri. +fn sum(x: T, y: T) -> T { + x + y +} +``` +8. 🌟🌟 +```rust,editable + +// REMEDIAȚI erorile. +struct Pair { + x: T, + y: T, +} + +impl Pair { + fn new(x: T, y: T) -> Self { + Self { + x, + y, + } + } +} + +impl Pair { + fn cmp_display(&self) { + if self.x >= self.y { + println!("The largest member is x = {:?}", self.x); + } else { + println!("The largest member is y = {:?}", self.y); + } + } +} + +struct Unit(i32); + +fn main() { + let pair = Pair{ + x: Unit(1), + y: Unit(3) + }; + + pair.cmp_display(); +} +``` + +9. 🌟🌟🌟 +```rust,editable + +// Completează spațiile libere pentru a face codul să funcționeze +fn example1() { + // T: Trait este modalitatea obișnuită de utilizare. + // T: Fn(u32) -> u32 specifică că putem trece doar o închidere la T. + struct Cacher u32> { + calculation: T, + value: Option, + } + + impl u32> Cacher { + fn new(calculation: T) -> Cacher { + Cacher { + calculation, + value: None, + } + } + + fn value(&mut self, arg: u32) -> u32 { + match self.value { + Some(v) => v, + None => { + let v = (self.calculation)(arg); + self.value = Some(v); + v + }, + } + } + } + + let mut cacher = Cacher::new(|x| x+1); + assert_eq!(cacher.value(10), __); + assert_eq!(cacher.value(15), __); +} + + +fn example2() { + // Putem folosi și where pentru a construi T. + struct Cacher + where T: Fn(u32) -> u32, + { + calculation: T, + value: Option, + } + + impl Cacher + where T: Fn(u32) -> u32, + { + fn new(calculation: T) -> Cacher { + Cacher { + calculation, + value: None, + } + } + + fn value(&mut self, arg: u32) -> u32 { + match self.value { + Some(v) => v, + None => { + let v = (self.calculation)(arg); + self.value = Some(v); + v + }, + } + } + } + + let mut cacher = Cacher::new(|x| x+1); + assert_eq!(cacher.value(20), __); + assert_eq!(cacher.value(25), __); +} + + + +fn main() { + example1(); + example2(); + + println!("Success!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/global-variables.md b/ro-RO/src/global-variables.md new file mode 100644 index 000000000..ad85421d3 --- /dev/null +++ b/ro-RO/src/global-variables.md @@ -0,0 +1 @@ +# Global variables diff --git a/ro-RO/src/lifetime/advance.md b/ro-RO/src/lifetime/advance.md new file mode 100644 index 000000000..0132f76d6 --- /dev/null +++ b/ro-RO/src/lifetime/advance.md @@ -0,0 +1,284 @@ +# Advance în durata de viață + +## Limitele de tipuri +La fel ca tipurile generice pot fi limitate, duratele de viață pot fi, de asemenea, limitate după cum urmează: +- T: `'a` - toate referințele din 'T' trebuie să supraviețuiască duratei de viață `'a` +- T: Trait + `'a`:' 'T' trebuie să implementeze trăsătura Trait, iar toate referințele din 'T' trebuie să supraviețuiască `'a` + +**Exemplu** +```rust,editable +use std::fmt::Debug; // Trăsătură pentru a limita. + +#[derive(Debug)] +struct Ref<'a, T: 'a>(&'a T); +/// `Ref` conține o referință la un tip generic `T` cu o durată de viață necunoscută `'a`. +// `T` este limitat astfel încât orice *referințe* în `T` trebuie să supraviețuiască `'a`. +// În plus, durata de viață a `Ref` nu poate depăși `'a`. + +// Funcție generică care tipărește utilizând trăsătura `Debug`. +fn print(t: T) where + T: Debug { + println!("`print`: t is {:?}", t); +} + +// Aici se ia o referință la `T` unde `T` implementează `Debug` și toate *referințele* +// din `T` supraviețuiesc lui `'a`. În plus, `'a` trebuie să supraviețuiască funcției. +fn print_ref<'a, T>(t: &'a T) where + T: Debug + 'a { + println!("`print_ref`: t is {:?}", t); +} + +fn main() { + let x = 7; + let ref_x = Ref(&x); + + print_ref(&ref_x); + print(ref_x); +} +``` + +1. 🌟 +```rust,editable +/* Adăugați durata de viață la structură: +1. `r` și `s` trebuie să aibă durate de viață diferite +2. durata de viață a `s` este mai mare decât cea a 'r' +*/ +struct DoubleRef { + r: &T, + s: &T +} +fn main() { + println!("Success!") +} +``` + + +2. 🌟🌟 +```rust,editable +/* Adăugați limite de trăsături pentru a face codul să funcționeze */ +struct ImportantExcerpt<'a> { + part: &'a str, +} + +impl<'a, 'b> ImportantExcerpt<'a> { + fn announce_and_return_part(&'a self, announcement: &'b str) -> &'b str { + println!("Attention please: {}", announcement); + self.part + } +} + +fn main() { + println!("Success!") +} +``` + +3. 🌟🌟 +```rust,editable +/* Adăugați limite de trăsături pentru a face codul să funcționeze */ +fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) { + y = x; + let r: &'b &'a i32 = &&0; +} + +fn main() { + println!("Success!") +} +``` + +## HRTB (Higher-ranked trait bounds) +Limitele de tip pot fi mai înalte decât duratele de viață. Aceste limite specifică faptul că o limită este valabilă pentru toate duratele de viață. De exemplu, o limită cum ar fi `for<'a> &'a T: PartialEq` ar necesita o implementare ca: + +```rust +impl<'a> PartialEq for &'a T { + // ... +} +``` + +ași apoi ar putea fi folosită pentru a compara un `&'a` `T` cu orice durată de viață față de un `i32`. + +Doar o limită mai înaltă poate fi folosită aici, deoarece durata de viață a referinței este mai scurtă decât orice posibil parametru de durată de viață al funcției. + +4. 🌟🌟🌟 +```rust,editable +/* Adăugați HRTB pentru a face codul să funcționeze! */ +fn call_on_ref_zero<'a, F>(f: F) where F: Fn(&'a i32) { + let zero = 0; + f(&zero); +} + +fn main() { + println!("Success!"); +} +``` +## NLL (Non-Lexical Lifetime) +Înainte de a explica NLL, să vedem mai întâi un cod: +```rust +fn main() { + let mut s = String::from("hello"); + + let r1 = &s; + let r2 = &s; + println!("{} and {}", r1, r2); + + let r3 = &mut s; + println!("{}", r3); +} +``` + +Bazat pe cunoștințele noastre actuale, acest cod va cauza o eroare datorită încălcării regulilor de împrumut în Rust. + +Dar dacă îl executați cu `cargo run`, totul va fi în regulă, așa că ce se întâmplă aici? + +Capacitatea compilatorului de a determina că o referință nu este folosită într-un punct înainte de sfârșitul domeniului de valabilitate se numește **Non-Lexical Lifetimes** (**NLL** în scurt). + +Cu această capacitate, compilatorul știe când este ultima dată când o referință este utilizată și optimizează regulile de împrumut pe baza acestei cunoștințe. + +```rust +let mut u = 0i32; +let mut v = 1i32; +let mut w = 2i32; + +// durata de viață a `a` = α ∪ β ∪ γ +let mut a = &mut u; // --+ α. durata de viață a `&mut u` --+ durata lexicală "a" a `&mut u`,`&mut u`, `&mut w` și `a` +use(a); // | | +*a = 3; // <-----------------+ | +... // | +a = &mut v; // --+ β. durata de viață a `&mut v` +use(a); // | | +*a = 4; // <-----------------+ | +... // | +a = &mut w; // --+ γ. durata de viață a `&mut w` +use(a); // | | +*a = 5; // <-----------------+ <--------------------------+ +``` + +## Reborrow +După învățarea NLL, putem înțelege ușor reborrow acum. + +**Exemplu** +```rust +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +impl Point { + fn move_to(&mut self, x: i32, y: i32) { + self.x = x; + self.y = y; + } +} + +fn main() { + let mut p = Point { x: 0, y: 0 }; + let r = &mut p; + // Aici vine reborrow + let rr: &Point = &*r; + + println!("{:?}", rr); //Reborrow se termină aici, NLL introdus + + // Reborrow s-a terminat, acum putem continua să folosim `r` + r.move_to(10, 10); + println!("{:?}", r); +} +``` + + +5. 🌟🌟 +```rust,editable +/* Faceți-l să funcționeze prin reordonarea unor coduri */ +fn main() { + let mut data = 10; + let ref1 = &mut data; + let ref2 = &mut *ref1; + + *ref1 += 1; + *ref2 += 2; + + println!("{}", data); +} +``` + + +## Durată de viață nelimitată +Vezi mai multe informații în [Nomicon - Unbounded Lifetimes](https://doc.rust-lang.org/nomicon/unbounded-lifetimes.html). + + +## More elision rules + +```rust +impl<'a> Reader for BufReader<'a> { + // 'a nu este folosit în metodele următoare +} + +// poate fi scris ca: +impl Reader for BufReader<'_> { + +} +``` + +```rust +// Rust 2015 +struct Ref<'a, T: 'a> { + field: &'a T +} + +// Rust 2018 +struct Ref<'a, T> { + field: &'a T +} +``` + + +## Un exercițiu dificil + +6. 🌟🌟🌟🌟 +```rust,editable +/* Faceți-l să funcționeze */ +struct Interface<'a> { + manager: &'a mut Manager<'a> +} + +impl<'a> Interface<'a> { + pub fn noop(self) { + println!("interface consumed"); + } +} + +struct Manager<'a> { + text: &'a str +} + +struct List<'a> { + manager: Manager<'a>, +} + +impl<'a> List<'a> { + pub fn get_interface(&'a mut self) -> Interface { + Interface { + manager: &mut self.manager + } + } +} + +fn main() { + let mut list = List { + manager: Manager { + text: "hello" + } + }; + + list.get_interface().noop(); + + println!("Interface should be dropped here and the borrow released"); + + use_list(&list); +} + +fn use_list(list: &List) { + println!("{}", list.manager.text); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/lifetime/basic.md b/ro-RO/src/lifetime/basic.md new file mode 100644 index 000000000..cf07adb0f --- /dev/null +++ b/ro-RO/src/lifetime/basic.md @@ -0,0 +1,360 @@ +## Durată de viață +Compilatorul utilizează durata de viață pentru a asigura că toate împrumuturile sunt valide. În mod obișnuit, durata de viață a unei variabile începe când este creată și se încheie când este distrusă. + +## Domeniul de viață +1. 🌟 +```rust,editable +/* Adăugați adnotările pentru duratele de viață ale `i` și `borrow2` */ + +// Duratele de viață sunt adnotate mai jos cu linii care indică crearea +// și distrugerea fiecărei variabile. +// `i` are cea mai lungă durată de viață pentru că domeniul său încadrează +// complet atât `borrow1`, cât și `borrow2`. Durata lui `borrow1` comparativ +// cu cea a lui `borrow2` este irelevantă, deoarece acestea sunt distincte. +fn main() { + let i = 3; + { + let borrow1 = &i; // // Durata de viață a lui `borrow1` începe. ──┐ + // │ + println!("borrow1: {}", borrow1); // │ + } // `borrow1` se încheie ────────────────────────────────────────────┘ + { + let borrow2 = &i; + + println!("borrow2: {}", borrow2); + } +} +``` + +2. 🌟🌟 + +**Exemplu** +```rust +{ + let x = 5; // ----------+-- 'b + // | + let r = &x; // --+-- 'a | + // | | + println!("r: {}", r); // | | + // --+ | +} // ----------+ +``` + + +```rust,editable +/* Adăugați adnotările pentru `r` și `x` ca mai sus și explicați de ce acest cod nu compilează din perspectiva duratei de viață. */ + +fn main() { + { + let r; // ---------+-- 'a + // | + { // | + let x = 5; // -+-- 'b | + r = &x; // | | + } // -+ | + // | + println!("r: {}", r); // | + } // ---------+ +} +``` + +## Adnotarea Duratei de Viață +**Verificatorul de împrumuturi utilizează adnotările explicite ale duratei de viață** pentru a determina cât timp trebuie să fie valabilă o referință. + +Dar pentru noi, utilizatorii, în majoritatea cazurilor, nu este nevoie să adnotăm durata de viață, deoarece există mai multe reguli de omisiune, iar înainte de a învăța aceste reguli, trebuie să știm cum să adnotăm manual durata de viață. + +#### Funcții +Ignorând regulile de omisiune, duratele de viață în semnăturile funcțiilor au câteva constrângeri: + +- Orice referință trebuie să aibă o durată de viață adnotată. +- Oricare referință care este returnată trebuie să aibă aceeași durată de viață ca una dintre intrările sau să fie statică. + +**Exemplu** +```rust,editable +// O referință de intrare cu durata de viață `'a`, care trebuie să trăiască +// cel puțin pe durata funcției. +fn print_one<'a>(x: &'a i32) { + println!("`print_one`: x is {}", x); +} + +// Referințe mutable sunt posibile și cu durate de viață. +fn add_one<'a>(x: &'a mut i32) { + *x += 1; +} + +// Mai multe elemente cu durate de viață diferite. În acest caz, +// ar fi în regulă ca ambele să aibă aceeași durată de viață `'a`, dar +// în cazuri mai complexe, pot fi necesare durate de viață diferite. +fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) { + println!("`print_multi`: x is {}, y is {}", x, y); +} + +// Returnarea referințelor care au fost trecute ca intrări este acceptabilă. +// Cu toate acestea, trebuie returnată durata de viață corectă. +fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x } + +fn main() { + let x = 7; + let y = 9; + + print_one(&x); + print_multi(&x, &y); + + let z = pass_x(&x, &y); + print_one(z); + + let mut t = 3; + add_one(&mut t); + print_one(&t); +} +``` + +3. 🌟 +```rust,editable +/* Faceți-l să funcționeze adăugând adnotarea adecvată pentru durata de viață */ +fn longest(x: &str, y: &str) -> &str { + if x.len() > y.len() { + x + } else { + y + } +} + +fn main() {} +``` +4. 🌟🌟🌟 +```rust,editable +// `'a` trebuie să trăiască mai mult decât funcția. +// Aici, `&String::from("foo")` ar crea un `String`, urmat de un +// referință. Apoi datele sunt abandonate la ieșirea din domeniu, lăsând +// o referință către date invalide pentru a fi returnată. + +/* Reparați eroarea în trei moduri */ +fn invalid_output<'a>() -> &'a String { + &String::from("foo") +} + +fn main() { +} +``` + +5. 🌟🌟 +```rust,editable +// `print_refs` primește două referințe la `i32` care au durate de viață diferite +// `'a` și `'b`. Aceste două durate de viață trebuie să fie ambele cel puțin +// la fel de lungi ca funcția `print_refs`. +fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) { + println!("x is {} and y is {}", x, y); +} + +/* Faceți-l să funcționeze */ +// O funcție care nu primește argumente, dar are un parametru de durată de viață `'a`. +fn failed_borrow<'a>() { + let _x = 12; + + // EROARE: `_x` nu trăiește destul de mult + let y: &'a i32 = &_x; + // Încercarea de a utiliza durata de viață `'a` ca adnotare de tip explicită + // în interiorul funcției va eșua pentru că durata de viață a `&_x` este mai scurtă + // decât `'a`. O durată de viață scurtă nu poate fi transformată într-una mai lungă. +} + +fn main() { + let (four, nine) = (4, 9); + + // Împrumuturile (`&`) ale ambelor variabile sunt trecute în funcție. + print_refs(&four, &nine); + // Orice intrare împrumutată trebuie să supraviețuiască împrumutătorului. + // Cu alte cuvinte, durata de viață a lui `four` și `nine` trebuie să + // fie mai lungă decât cea a funcției `print_refs`. + + failed_borrow(); + // `failed_borrow` nu conține referințe pentru a forța `'a` să fie + // mai lung decât durata de viață a funcției, dar `'a` este mai lung. + // Deoarece durata de viață nu este niciodată restricționată, aceasta + // devine implicită `'static`. +} +``` + +#### Structs +6. 🌟 +```rust,editable +/* Faceți-l să funcționeze adăugând adnotarea adecvată pentru durata de viață */ + +// Un tip `Borrowed` care conține o referință la un +// `i32`. Referința la `i32` trebuie să trăiască mai mult decât `Borrowed`. +#[derive(Debug)] +struct Borrowed(&i32); + +// Similar, ambele referințe aici trebuie să trăiască mai mult decât această structură. +#[derive(Debug)] +struct NamedBorrowed { + x: &i32, + y: &i32, +} + +// Un enum care este fie un `i32`, fie o referință la unul. +#[derive(Debug)] +enum Either { + Num(i32), + Ref(&i32), +} + +fn main() { + let x = 18; + let y = 15; + + let single = Borrowed(&x); + let double = NamedBorrowed { x: &x, y: &y }; + let reference = Either::Ref(&x); + let number = Either::Num(y); + + println!("x is borrowed in {:?}", single); + println!("x and y are borrowed in {:?}", double); + println!("x is borrowed in {:?}", reference); + println!("y is *not* borrowed in {:?}", number); +} +``` + + +7. 🌟🌟 +```rust,editable +/* Faceți-l să funcționeze */ + +#[derive(Debug)] +struct NoCopyType {} + +#[derive(Debug)] +struct Example<'a, 'b> { + a: &'a u32, + b: &'b NoCopyType +} + +fn main() +{ + /* 'a legat de stiva fn-main */ + let var_a = 35; + let example: Example; + + { + /* Durata de viață 'b legată de un nou cadru/scope */ + let var_b = NoCopyType {}; + + /* fixme */ + example = Example { a: &var_a, b: &var_b }; + } + + println!("(Success!) {:?}", example); +} +``` + + +8. 🌟🌟 +```rust,editable + +#[derive(Debug)] +struct NoCopyType {} + +#[derive(Debug)] +#[allow(dead_code)] +struct Example<'a, 'b> { + a: &'a u32, + b: &'b NoCopyType +} + +/* Fixați semnătura funcției */ +fn fix_me(foo: &Example) -> &NoCopyType +{ foo.b } + +fn main() +{ + let no_copy = NoCopyType {}; + let example = Example { a: &1, b: &no_copy }; + fix_me(&example); + println!("Success!") +} +``` + +## Metodă +Metodele sunt adnotate similar cu funcțiile. + +**Exemplu** +```rust,editable +struct Owner(i32); + +impl Owner { + // Adnotare pentru duratele de viață la fel ca într-o funcție independentă. + fn add_one<'a>(&'a mut self) { self.0 += 1; } + fn print<'a>(&'a self) { + println!("`print`: {}", self.0); + } +} + +fn main() { + let mut owner = Owner(18); + + owner.add_one(); + owner.print(); +} +``` + +9. 🌟🌟 +```rust,editable +/* Faceți-l să funcționeze adăugând adnotările adecvate pentru durata de viață */ +struct ImportantExcerpt { + part: &str, +} + +impl ImportantExcerpt { + fn level(&'a self) -> i32 { + 3 + } +} + +fn main() {} +``` + +## Omisiune (Elision) +Unele modele de durate de viață sunt atât de comune încât verificatorul de împrumuturi va permite să le omiteți pentru a salva tastarea și a îmbunătăți citirea. + +Acest lucru este cunoscut sub numele de **omisiune**. Omisiunea există în Rust doar pentru că aceste modele sunt comune. + +Pentru o înțelegere mai cuprinzătoare a omisiunii, vă rugăm să consultați [omisiunea duratei de viață](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-elision) în cartea oficială. + +10. 🌟🌟 +```rust,editable +/* Eliminați toate duratele de viață care pot fi omise */ + +fn input<'a>(x: &'a i32) { + println!("`annotated_input`: {}", x); +} + +fn pass<'a>(x: &'a i32) -> &'a i32 { x } + +fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { + x +} + +struct Owner(i32); + +impl Owner { + // Adnotați duratele de viață la fel ca într-o funcție independentă. + fn add_one<'a>(&'a mut self) { self.0 += 1; } + fn print<'a>(&'a self) { + println!("`print`: {}", self.0); + } +} + +struct Person<'a> { + age: u8, + name: &'a str, +} + +enum Either<'a> { + Num(i32), + Ref(&'a i32), +} + +fn main() {} +``` +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/lifetime/intro.md b/ro-RO/src/lifetime/intro.md new file mode 100644 index 000000000..fe312f434 --- /dev/null +++ b/ro-RO/src/lifetime/intro.md @@ -0,0 +1,5 @@ +# Durată de viață +Resurse de învățare: +- Engleză: [Rust Book 10.3](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html) +- Chineză simplificată: [Rust语言圣经 - 生命周期](https://course.rs/advance/lifetime/intro.html) + diff --git a/ro-RO/src/lifetime/static.md b/ro-RO/src/lifetime/static.md new file mode 100644 index 000000000..23279d6e3 --- /dev/null +++ b/ro-RO/src/lifetime/static.md @@ -0,0 +1,198 @@ +# &'static și T: 'static +`'static` este un nume rezervat pentru durata de viață și l-ați putut întâlni de mai multe ori: +```rust +// O referință cu durata de viață 'static: +let s: &'static str = "hello world"; + +// 'static ca parte a unei constrângeri de trăsătură (trait bound): +fn generic(x: T) where T: 'static {} +``` + +Chiar dacă toate sunt 'static, ele sunt subtil diferite. + +## &'static +Ca durată de viață pentru o referință, &'static indică faptul că datele la care se referă referința trăiesc pe toată durata de execuție a programului. Cu toate acestea, poate fi încă coercită (coerced/constrânsă) la o durată de viață mai scurtă. + + + +1. 🌟🌟 Există mai multe moduri de a crea o variabilă cu durată de viață `'static`, două dintre ele sunt stocate în memoria de tip citire a binarului. + +```rust,editable + +/* Completați spațiile libere în două moduri */ +fn main() { + __; + need_static(v); + + println!("Success!") +} + +fn need_static(r : &'static str) { + assert_eq!(r, "hello"); +} +``` + +2. 🌟🌟🌟🌟 O altă modalitate de a obține durata de viață `'static` este utilizarea `Box::leak`. +```rust,editable +#[derive(Debug)] +struct Config { + a: String, + b: String, +} +static mut config: Option<&mut Config> = None; + +/* Faceți-l să funcționeze fără a schimba semnăturile funcțiilor din `init` */ +fn init() -> Option<&'static mut Config> { + Some(&mut Config { + a: "A".to_string(), + b: "B".to_string(), + }) +} + + +fn main() { + unsafe { + config = init(); + + println!("{:?}",config) + } +} +``` + +3. 🌟 `&'static` indică doar faptul că datele pot trăi pentru totdeauna, nu și referința. Aceasta din urmă va fi restricționată de domeniul său. +```rust,editable +fn main() { + { + // Creați un șir literal și tipăriți-l: + let static_string = "I'm in read-only memory"; + println!("static_string: {}", static_string); + + // Când `static_string` iese din domeniu, referința + // nu mai poate fi utilizată, dar datele rămân în binar. + } + + println!("static_string reference remains alive: {}", static_string); +} +``` + +4. `&'static` poate fi coercitată la o durată de viață mai scurtă. + +**Exemplu** +```rust,editable +// Creați o constantă cu durata de viață `'static`. +static NUM: i32 = 18; + +// Returnează o referință la `NUM` în care durata de viață `'static` +// este coercitată la cea a argumentului de intrare. +fn coerce_static<'a>(_: &'a i32) -> &'a i32 { + &NUM +} + +fn main() { + { + // Faceți un număr întreg pentru a-l folosi în `coerce_static`: + let lifetime_num = 9; + + // Coercitați `NUM` la durata de viață a lui `lifetime_num`: + let coerced_static = coerce_static(&lifetime_num); + + println!("coerced_static: {}", coerced_static); + } + + println!("NUM: {} stays accessible!", NUM); +} +``` + + + +## T: 'static +Ca o constrângere a trăsăturii, înseamnă că tipul nu conține nicio referință non-'static. De exemplu, receptorul poate reține tipul pentru cât timp doresc și acesta nu va deveni niciodată invalid până când îl abandonează. + +Este important să înțelegeți că acest lucru înseamnă că orice date deținute întotdeauna trec printr-o durată de viață 'static, dar o referință la aceste date deținute de obicei nu o face. + + +5. 🌟🌟 +```rust,editable +/* Faceți-l să funcționeze */ +use std::fmt::Debug; + +fn print_it( input: T) { + println!( "'static value passed in is: {:?}", input ); +} + +fn print_it1( input: impl Debug + 'static ) { + println!( "'static value passed in is: {:?}", input ); +} + + +fn print_it2( input: &T) { + println!( "'static value passed in is: {:?}", input ); +} + +fn main() { + // i este deținut și nu conține referințe, așa că este 'static: + let i = 5; + print_it(i); + + // ups, &i are doar durata de viață definită de domeniul + // main(), deci nu este 'static: + print_it(&i); + + print_it1(&i); + + // dar acesta FUNCȚIONEAZĂ! + print_it2(&i); +} +``` + + +6. 🌟🌟🌟 +```rust,editable +use std::fmt::Display; + +fn main() { + let mut string = "First".to_owned(); + + string.push_str(string.to_uppercase().as_str()); + print_a(&string); + print_b(&string); + print_c(&string); // Eroare la compilare + print_d(&string); // Eroare la compilare + print_e(&string); + print_f(&string); + print_g(&string); // Eroare la compilare +} + +fn print_a(t: &T) { + println!("{}", t); +} + +fn print_b(t: &T) +where + T: Display + 'static, +{ + println!("{}", t); +} + +fn print_c(t: &'static dyn Display) { + println!("{}", t) +} + +fn print_d(t: &'static impl Display) { + println!("{}", t) +} + +fn print_e(t: &(dyn Display + 'static)) { + println!("{}", t) +} + +fn print_f(t: &(impl Display + 'static)) { + println!("{}", t) +} + +fn print_g(t: &'static String) { + println!("{}", t); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/macro.md b/ro-RO/src/macro.md new file mode 100644 index 000000000..20503ba45 --- /dev/null +++ b/ro-RO/src/macro.md @@ -0,0 +1 @@ +# macro diff --git a/ro-RO/src/method.md b/ro-RO/src/method.md new file mode 100644 index 000000000..83392d7d1 --- /dev/null +++ b/ro-RO/src/method.md @@ -0,0 +1,273 @@ +# Associated functions & Methods + +## Examples +```rust,editable +struct Point { + x: f64, + y: f64, +} + +// Implementation block, all `Point` associated functions & methods go in here. +impl Point { + // This is an "associated function" because this function is associated with + // a particular type, that is, Point. + // + // Associated functions don't need to be called with an instance. + // These functions are generally used like constructors. + fn origin() -> Point { + Point { x: 0.0, y: 0.0 } + } + + // Another associated function, taking two arguments: + fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } +} + +struct Rectangle { + p1: Point, + p2: Point, +} + +impl Rectangle { + // This is a method. + // `&self` is sugar for `self: &Self`, where `Self` is the type of the + // caller object. In this case `Self` = `Rectangle` + fn area(&self) -> f64 { + // `self` gives access to the struct fields via the dot operator. + let Point { x: x1, y: y1 } = self.p1; + let Point { x: x2, y: y2 } = self.p2; + + // `abs` is a `f64` method that returns the absolute value of the + // caller + ((x1 - x2) * (y1 - y2)).abs() + } + + fn perimeter(&self) -> f64 { + let Point { x: x1, y: y1 } = self.p1; + let Point { x: x2, y: y2 } = self.p2; + + 2.0 * ((x1 - x2).abs() + (y1 - y2).abs()) + } + + // This method requires the caller object to be mutable + // `&mut self` desugars to `self: &mut Self` + fn translate(&mut self, x: f64, y: f64) { + self.p1.x += x; + self.p2.x += x; + + self.p1.y += y; + self.p2.y += y; + } +} + +// `Pair` owns resources: two heap allocated integers. +struct Pair(Box, Box); + +impl Pair { + // This method "consumes" the resources of the caller object + // `self` desugars to `self: Self` + fn destroy(self) { + // Destructure `self` + let Pair(first, second) = self; + + println!("Destroying Pair({}, {})", first, second); + + // `first` and `second` go out of scope and get freed. + } +} + +fn main() { + let rectangle = Rectangle { + // Associated functions are called using double colons + p1: Point::origin(), + p2: Point::new(3.0, 4.0), + }; + + // Methods are called using the dot operator. + // Note that the first argument `&self` is implicitly passed, i.e. + // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)` + println!("Rectangle perimeter: {}", rectangle.perimeter()); + println!("Rectangle area: {}", rectangle.area()); + + let mut square = Rectangle { + p1: Point::origin(), + p2: Point::new(1.0, 1.0), + }; + + // Error! `rectangle` is immutable, but this method requires a mutable + // object. + //rectangle.translate(1.0, 0.0); + // TODO ^ Try uncommenting this line + + // Okay! Mutable objects can call mutable methods + square.translate(1.0, 1.0); + + let pair = Pair(Box::new(1), Box::new(2)); + + pair.destroy(); + + // Error! Previous `destroy` call "consumed" `pair` + //pair.destroy(); + // TODO ^ Try uncommenting this line +} +``` + +## Exercises + +### Method +1. 🌟🌟 Methods are similar to functions: Declare with `fn`, have parameters and a return value. Unlike functions, methods are defined within the context of a struct (or an enum or a trait object), and their first parameter is always `self`, which represents the instance of the struct the method is being called on. +```rust,editable +struct Rectangle { + width: u32, + height: u32, +} + +impl Rectangle { + // Complete the area method which return the area of a Rectangle. + fn area +} + +fn main() { + let rect1 = Rectangle { width: 30, height: 50 }; + + assert_eq!(rect1.area(), 1500); + + println!("Success!"); +} +``` + +2. 🌟🌟 `self` will take the ownership of current struct instance, however, `&self` will only borrow a reference from the instance. + +```rust,editable +// Only fill in the blanks, DON'T remove any line! +#[derive(Debug)] +struct TrafficLight { + color: String, +} + +impl TrafficLight { + pub fn show_state(__) { + println!("the current state is {}", __.color); + } +} +fn main() { + let light = TrafficLight{ + color: "red".to_owned(), + }; + // Don't take the ownership of `light` here. + light.show_state(); + // ... Otherwise, there will be an error below + println!("{:?}", light); +} +``` +3. 🌟🌟 The `&self` is actually short for `self: &Self`. Within an `impl` block, the type `Self` is an alias for the type that the `impl` block is for. Methods must have a parameter named `self` of type `Self` for their first parameter, so Rust lets you abbreviate this with only the name `self` in the first parameter spot. +```rust,editable +struct TrafficLight { + color: String, +} + +impl TrafficLight { + // Using `Self` to fill in the blank. + pub fn show_state(__) { + println!("the current state is {}", self.color); + } + + // Fill in the blank, DON'T use any variants of `Self`. + pub fn change_state(__) { + self.color = "green".to_string() + } +} +fn main() { + println!("Success!"); +} +``` + + +### Associated functions + +4. 🌟🌟 All functions defined within an `impl` block are called associated functions because they’re associated with the type named after the `impl`. We can define associated functions that don’t have `self` as their first parameter (and thus are not methods) because they don’t need an instance of the type to work with. + +```rust,editable +#[derive(Debug)] +struct TrafficLight { + color: String, +} + +impl TrafficLight { + // 1. Implement an associated function `new`, + // 2. It will return a TrafficLight contains color "red" + // 3. Must use `Self`, DONT use `TrafficLight` in fn signatures or body + pub fn new() + + pub fn get_state(&self) -> &str { + &self.color + } +} + +fn main() { + let light = TrafficLight::new(); + assert_eq!(light.get_state(), "red"); + + println!("Success!"); +} +``` + +### Multiple `impl` blocks +5. 🌟 Each struct is allowed to have multiple impl blocks. +```rust,editable + +struct Rectangle { + width: u32, + height: u32, +} + +// Using multiple `impl` blocks to rewrite the code below. +impl Rectangle { + fn area(&self) -> u32 { + self.width * self.height + } + + fn can_hold(&self, other: &Rectangle) -> bool { + self.width > other.width && self.height > other.height + } +} + + +fn main() { + println!("Success!"); +} +``` + +### Enums +6. 🌟🌟🌟 We can also implement methods for enums. + +```rust,editable + +#[derive(Debug)] +enum TrafficLightColor { + Red, + Yellow, + Green, +} + +// Implement TrafficLightColor with a method. +impl TrafficLightColor { + +} + +fn main() { + let c = TrafficLightColor::Yellow; + + assert_eq!(c.color(), "yellow"); + + println!("{:?}",c); +} +``` + +## Practice + +@todo + + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it \ No newline at end of file diff --git a/ro-RO/src/newtype-sized.md b/ro-RO/src/newtype-sized.md new file mode 100644 index 000000000..956684802 --- /dev/null +++ b/ro-RO/src/newtype-sized.md @@ -0,0 +1,204 @@ +# newtype and Sized + +## Newtype +The orphan rule tells us that we are allowed to implement a trait on a type as long as either the trait or the type are local to our crate. + +The **newtype pattern** can help us get around this restriction, which involves creating a new type in a **tuple struct**. + +1. 🌟 +```rust,editable +use std::fmt; + +/* Define the Wrapper type */ +__; + +// Display is an external trait +impl fmt::Display for Wrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[{}]", self.0.join(", ")) + } +} + +fn main() { + // Vec is an external type, so you cannot implement Display trait on Vec type + let w = Wrapper(vec![String::from("hello"), String::from("world")]); + println!("w = {}", w); +} +``` + +2. 🌟 Hide the methods of the original type. +```rust,editable +/* Make it workd */ +struct Meters(u32); + +fn main() { + let i: u32 = 2; + assert_eq!(i.pow(2), 4); + + let n = Meters(i); + // The `pow` method is defined on `u32` type, we can't directly call it + assert_eq!(n.pow(2), 4); +} +``` + +3. 🌟🌟 The `newtype` idiom gives compile time guarantees that the right type of value is supplied to a program. +```rust,editable +/* Make it work */ +struct Years(i64); + +struct Days(i64); + +impl Years { + pub fn to_days(&self) -> Days { + Days(self.0 * 365) + } +} + + +impl Days { + pub fn to_years(&self) -> Years { + Years(self.0 / 365) + } +} + +// An age verification function that checks age in years, must be given a value of type Years. +fn old_enough(age: &Years) -> bool { + age.0 >= 18 +} + +fn main() { + let age = Years(5); + let age_days = age.to_days(); + println!("Old enough {}", old_enough(&age)); + println!("Old enough {}", old_enough(&age_days)); +} +``` + +4. 🌟🌟 +```rust,editable +use std::ops::Add; +use std::fmt::{self, format}; + +struct Meters(u32); +impl fmt::Display for Meters { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "There are still {} meters left", self.0) + } +} + +impl Add for Meters { + type Output = Self; + + fn add(self, other: Meters) -> Self { + Self(self.0 + other.0) + } +} +fn main() { + let d = calculate_distance(Meters(10), Meters(20)); + assert_eq!(format!("{}",d), "There are still 30 meters left"); +} + +/* Implement calculate_distance */ +fn calculate_distance +``` + +## Type alias +Type alias is important to improve the readability of our code. + +```rust +type Thunk = Box; + +let f: Thunk = Box::new(|| println!("hi")); + +fn takes_long_type(f: Thunk) { + // --snip-- +} + +fn returns_long_type() -> Thunk { + // --snip-- +} +``` + +```rust +type Result = std::result::Result; +``` + +And Unlike newtype, type alias don't create new types, so the following code is valid: +```rust +type Meters = u32; + +let x: u32 = 5; +let y: Meters = 5; + +println!("x + y = {}", x + y); +``` + +5. 🌟 +```rust,editable +enum VeryVerboseEnumOfThingsToDoWithNumbers { + Add, + Subtract, +} + +/* Fill in the blank */ +__ + +fn main() { + // We can refer to each variant via its alias, not its long and inconvenient + // name. + let x = Operations::Add; +} +``` + +6. 🌟🌟 There are a few preserved aliases in Rust, one of which can be used in `impl` blocks. +```rust,editable +enum VeryVerboseEnumOfThingsToDoWithNumbers { + Add, + Subtract, +} + +impl VeryVerboseEnumOfThingsToDoWithNumbers { + fn run(&self, x: i32, y: i32) -> i32 { + match self { + __::Add => x + y, + __::Subtract => x - y, + } + } +} +``` + +## DST and unsized type +These concepts are complicated, so we are not going to explain here, but you can find them in [The Book](https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=DST#dynamically-sized-types-and-the-sized-trait). + +7. 🌟🌟🌟 Array with dynamic length is a Dynamic Sized Type ( DST ), we can't directly use it +```rust,editable +/* Make it work with const generics */ +fn my_function(n: usize) -> [u32; usize] { + [123; n] +} + +fn main() { + let arr = my_function(); + println!("{:?}",arr); +} +``` + +8. 🌟🌟 Slice is unsized type, but the reference of slice is not. +```rust,editable +/* Make it work with slice references */ +fn main() { + let s: str = "Hello there!"; + + let arr: [u8] = [1, 2, 3]; +} +``` + +9. 🌟🌟 Trait is also an unsized type +```rust,editable +/* Make it work in two ways */ +use std::fmt::Display; +fn foobar(thing: Display) {} + +fn main() { +} +``` \ No newline at end of file diff --git a/ro-RO/src/ownership/borrowing.md b/ro-RO/src/ownership/borrowing.md new file mode 100644 index 000000000..b0363b452 --- /dev/null +++ b/ro-RO/src/ownership/borrowing.md @@ -0,0 +1,186 @@ +# Referințe și Împrumutare + +### Referințe +1. 🌟 +```rust,editable + +fn main() { + let x = 5; + // Completați spațiile libere + let p = __; + + println!("the memory address of x is {:p}", p); // Una dintre posibilele ieșiri: 0x16fa3ac84 +} +``` + +2. 🌟 +```rust,editable + +fn main() { + let x = 5; + let y = &x; + + // Modificați doar această linie + assert_eq!(5, y); + + println!("Success!"); +} +``` + +3. 🌟 +```rust,editable + +// Corectați eroarea +fn main() { + let mut s = String::from("hello, "); + + borrow_object(s); + + println!("Success!"); +} + +fn borrow_object(s: &String) {} +``` + +4. 🌟 +```rust,editable + +// Corectați eroarea +fn main() { + let mut s = String::from("hello, "); + + push_str(s); + + println!("Success!"); +} + +fn push_str(s: &mut String) { + s.push_str("world") +} +``` + +5. 🌟🌟 +```rust,editable + +fn main() { + let mut s = String::from("hello, "); + + // Completați spațiile libere pentru a face ca codul să funcționeze + let p = __; + + p.push_str("world"); + + println!("Success!"); +} +``` + +#### Ref +`ref` poate fi folosit pentru a obține referințe la o valoare, similar cu `&`. + +6. 🌟🌟🌟 +```rust,editable + +fn main() { + let c = '中'; + + let r1 = &c; + // Completați spațiile libere, fără a schimba alte coduri + let __ r2 = c; + + assert_eq!(*r1, *r2); + + // Verificați egalitatea celor două șiruri de adrese + assert_eq!(get_addr(r1),get_addr(r2)); + + println!("Success!"); +} + +// Obțineți șirul de adresă de memorie +fn get_addr(r: &char) -> String { + format!("{:p}", r) +} +``` + +### Reguli de Împrumut +7. 🌟 +```rust,editable + +// Eliminați ceva pentru a face ca codul să funcționeze +// Nu ștergeți o linie întreagă! +fn main() { + let mut s = String::from("hello"); + + let r1 = &mut s; + let r2 = &mut s; + + println!("{}, {}", r1, r2); + + println!("Success!"); +} +``` + +#### Mutabilitate +8. 🌟 Eroare: Împrumutați un obiect imutabil ca mutabil +```rust,editable + +fn main() { + // Corectați eroarea modificând această linie + let s = String::from("hello, "); + + borrow_object(&mut s); + + println!("Success!"); +} + +fn borrow_object(s: &mut String) {} +``` + +9. 🌟🌟 Ok: Împrumutați un obiect mutabil ca imutabil +```rust,editable + +// Acest cod nu are erori! +fn main() { + let mut s = String::from("hello, "); + + borrow_object(&s); + + s.push_str("world"); + + println!("Success!"); +} + +fn borrow_object(s: &String) {} +``` + +### NLL (Non-Lexical Lifetimes) +10. 🌟🌟 +```rust,editable + +// Comentați o linie pentru a face ca codul să funcționeze +fn main() { + let mut s = String::from("hello, "); + + let r1 = &mut s; + r1.push_str("world"); + let r2 = &mut s; + r2.push_str("!"); + + println!("{}",r1); +} +``` + +11. 🌟🌟 +```rust,editable + +fn main() { + let mut s = String::from("hello, "); + + let r1 = &mut s; + let r2 = &mut s; + + // Adăugați o linie mai jos pentru a obține o eroare de compilator: nu se poate împrumuta `s` ca mutabil de mai multe ori simultan + // Nu puteți utiliza r1 și r2 în același timp +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/ownership/intro.md b/ro-RO/src/ownership/intro.md new file mode 100644 index 000000000..5b3e57b67 --- /dev/null +++ b/ro-RO/src/ownership/intro.md @@ -0,0 +1,5 @@ +# Proprietatea și Împrumutul +Resurse de învățare: +- Engleză: [Rust Book 4.1-4.4](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) +- Chineză simplifticată: [Rust语言圣经 - 所有权与借用](https://course.rs/basic/ownership/index.html) + diff --git a/ro-RO/src/ownership/ownership.md b/ro-RO/src/ownership/ownership.md new file mode 100644 index 000000000..cb0d27417 --- /dev/null +++ b/ro-RO/src/ownership/ownership.md @@ -0,0 +1,170 @@ +# Proprietate (Ownership) + +1. 🌟🌟 +```rust,editable + +fn main() { + // Folosiți cât mai multe abordări posibile pentru a face ca acest cod să funcționeze + let x = String::from("hello, world"); + let y = x; + println!("{},{}",x,y); +} +``` + +2. 🌟🌟 +```rust,editable +// Nu modificați codul în funcția main! +fn main() { + let s1 = String::from("hello, world"); + let s2 = take_ownership(s1); + + println!("{}", s2); +} + +// Modificați doar codul de mai jos! +fn take_ownership(s: String) { + println!("{}", s); +} +``` + + +3. 🌟🌟 +```rust,editable + +fn main() { + let s = give_ownership(); + println!("{}", s); +} + +// Modificați doar codul de mai jos! +fn give_ownership() -> String { + let s = String::from("hello, world"); + // Convertiți String în Vec + let _s = s.into_bytes(); + s +} +``` + +4. 🌟🌟 +```rust,editable +// Corectați eroarea fără a elimina linia de cod +fn main() { + let s = String::from("hello, world"); + + print_str(s); + + println!("{}", s); +} + +fn print_str(s: String) { + println!("{}",s) +} +``` + +5. 🌟🌟 +```rust,editable +// Nu folosiți clone, folosiți copy în schimb +fn main() { + let x = (1, 2, (), "hello".to_string()); + let y = x.clone(); + println!("{:?}, {:?}", x, y); +} +``` + +#### Mutabilitate +Mutabilitatea poate fi schimbată atunci când proprietatea este transferată. + +6. 🌟 +```rust,editable + +fn main() { + let s = String::from("hello, "); + + // Modificați doar această linie! + let s1 = s; + + s1.push_str("world"); + + println!("Success!"); +} +``` + +7. 🌟🌟🌟 +```rust,editable + +fn main() { + let x = Box::new(5); + + let ... // Implementați această linie. Nu schimbați alte linii! + + *y = 4; + + assert_eq!(*x, 5); + + println!("Success!"); +} +``` + +### Mutare Parțială +În cadrul destrămării unei variabile unice, atât legăturile de tip mutabil, cât și cele de tip referință pot fi folosite în același timp. Acest lucru va rezulta într-o mutare parțială a variabilei, ceea ce înseamnă că părți ale variabilei vor fi mutate în timp ce alte părți rămân. Într-un astfel de caz, variabila părinte nu poate fi folosită ulterior ca întreg, însă părțile care sunt doar referențiate (și nu mutate) pot fi în continuare utilizate. + +#### Exemplu +```rust,editable + +fn main() { + #[derive(Debug)] + struct Person { + name: String, + age: Box, + } + + let person = Person { + name: String::from("Alice"), + age: Box::new(20), + }; + + // `name` este mutat din person, dar `age` este referențiată + let Person { name, ref age } = person; + + println!("The person's age is {}", age); + + println!("The person's name is {}", name); + + // Eroare! împrumut de valoare parțial mutată: `person` mutare parțială apare + //println!("The person struct is {:?}", person); + + // `person`nu poate fi folosită, dar `person.age` poate fi folosită deoarece nu este mutată + println!("The person's age from person struct is {}", person.age); +} +``` + +#### Exerciții + +8. 🌟 +```rust,editable + +fn main() { + let t = (String::from("hello"), String::from("world")); + + let _s = t.0; + + // Modificați doar această linie, nu folosiți `_s` + println!("{:?}", t); +} +``` + +9. 🌟🌟 +```rust,editable + +fn main() { + let t = (String::from("hello"), String::from("world")); + + // Completați spațiile libere + let (__, __) = __; + + println!("{:?}, {:?}, {:?}", s1, s2, t); // -> "hello", "world", ("hello", "world") +} +``` + + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/pattern-match/intro.md b/ro-RO/src/pattern-match/intro.md new file mode 100644 index 000000000..5a8b1cc35 --- /dev/null +++ b/ro-RO/src/pattern-match/intro.md @@ -0,0 +1,6 @@ +# Pattern Match +Resurse de învățare: +- Engleză: [Rust Book 18](https://doc.rust-lang.org/book/ch18-00-patterns.html) +- Chineză simplifticată: [Rust语言圣经 - 模式匹配](https://course.rs/basic/match-pattern/intro.html) + + diff --git a/ro-RO/src/pattern-match/match-iflet.md b/ro-RO/src/pattern-match/match-iflet.md new file mode 100644 index 000000000..e7121d881 --- /dev/null +++ b/ro-RO/src/pattern-match/match-iflet.md @@ -0,0 +1,209 @@ +# Match, if let + +### Match +1. 🌟🌟 +```rust,editable + +// Completați spațiile libere +enum Direction { + East, + West, + North, + South, +} + +fn main() { + let dire = Direction::South; + match dire { + Direction::East => println!("East"), + __ => { // Se potrivește cu Sud sau Nord aici + println!("South or North"); + }, + _ => println!(__), + }; +} +``` + +2. 🌟🌟 `Match` este o expresie, așadar o putem folosi în asignări. +```rust,editable + +fn main() { + let boolean = true; + + // Completați spațiile libere cu o expresie match: + // + // boolean = true => binary = 1 + // boolean = false => binary = 0 + let binary = __; + + assert_eq!(binary, 1); + + println!("Success!"); +} +``` + +3. 🌟🌟 Utilizarea match pentru a obține datele pe care o variantă enum o deține. +```rust,editable + +// Completați spațiile libere +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} + +fn main() { + let msgs = [ + Message::Quit, + Message::Move{x:1, y:3}, + Message::ChangeColor(255,255,0) + ]; + + for msg in msgs { + show_message(msg) + } + + println!("Success!"); +} + +fn show_message(msg: Message) { + match msg { + __ => { // se potrivește cu Message::Move + assert_eq!(a, 1); + assert_eq!(b, 3); + }, + Message::ChangeColor(_, g, b) => { + assert_eq!(g, __); + assert_eq!(b, __); + } + __ => println!("no data in these variants") + } +} +``` + +### matches! +[`matches!`](https://doc.rust-lang.org/stable/core/macro.matches.html) pare a fi match, dar poate face ceva diferit. + +4. 🌟🌟 +```rust,editable + +fn main() { + let alphabets = ['a', 'E', 'Z', '0', 'x', '9' , 'Y']; + + // Completați spațiile libere cu `matches!` pentru a face codul să funcționeze + for ab in alphabets { + assert!(__) + } + + println!("Success!"); +} +``` + +5. 🌟🌟 +```rust,editable + +enum MyEnum { + Foo, + Bar +} + +fn main() { + let mut count = 0; + + let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo]; + for e in v { + if e == MyEnum::Foo { // Remediați eroarea schimbând doar această linie + count += 1; + } + } + + assert_eq!(count, 2); + + println!("Success!"); +} +``` + +### If let +Pentru unele cazuri, atunci când potrivirea enumurilor este prea grea, putem folosi `if let`. + +6. 🌟 +```rust,editable + +fn main() { + let o = Some(7); + + // Eliminați blocul `match` întreg, folosind `if let` în schimb + match o { + Some(i) => { + println!("This is a really long string and `{:?}`", i); + + println!("Success!"); + } + _ => {} + }; +} +``` + +7. 🌟🌟 +```rust,editable + +// Completați spațiile libere +enum Foo { + Bar(u8) +} + +fn main() { + let a = Foo::Bar(1); + + __ { + println!("foobar holds the value: {}", i); + + println!("Success!"); + } +} +``` + +8. 🌟🌟 +```rust,editable + +enum Foo { + Bar, + Baz, + Qux(u32) +} + +fn main() { + let a = Foo::Qux(10); + + // Eliminați codurile de mai jos, folosind `match` în schimb + if let Foo::Bar = a { + println!("match foo::bar") + } else if let Foo::Baz = a { + println!("match foo::baz") + } else { + println!("match others") + } +} +``` + +### Shadowing +9. 🌟🌟 +```rust,editable + +// Remediați erorile în locul lor +fn main() { + let age = Some(30); + if let Some(age) = age { // Creați o nouă variabilă cu același nume ca și `age` anterior + assert_eq!(age, Some(30)); + } // Noua variabilă `age` iese din scop aici + + match age { + // Match poate introduce, de asemenea, o nouă variabilă umbrită + Some(age) => println!("age is a new variable, it's value is {}",age), + _ => () + } + } +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/pattern-match/patterns.md b/ro-RO/src/pattern-match/patterns.md new file mode 100644 index 000000000..596d5d73d --- /dev/null +++ b/ro-RO/src/pattern-match/patterns.md @@ -0,0 +1,120 @@ +# Pattern-uri (Patterns) + +1. 🌟🌟 Folosiți `|` pentru a potrivi mai multe valori, utilizați `..=` pentru a potrivi o gamă inclusivă. +```rust,editable + +fn main() {} +fn match_number(n: i32) { + match n { + // Potriviți o singură valoare + 1 => println!("One!"), + // Completați spațiile libere cu `|`, NU folosiți `..` sau `..=` + __ => println!("match 2 -> 5"), + // Potriviți o gamă inclusivă + 6..=10 => { + println!("match 6 -> 10") + }, + _ => { + println!("match -infinite -> 0 or 11 -> +infinite") + } + } +} +``` + +2. 🌟🌟🌟 Operatorul `@` ne permite să creăm o variabilă care reține o valoare, în același timp când testăm dacă acea valoare se potrivește cu un model. +```rust,editable + +struct Point { + x: i32, + y: i32, +} + +fn main() { + // Completați spațiile libere pentru a face ca p să se potrivească cu al doilea braț + let p = Point { x: __, y: __ }; + + match p { + Point { x, y: 0 } => println!("On the x axis at {}", x), + // Al doilea braț + Point { x: 0..=5, y: y@ (10 | 20 | 30) } => println!("On the y axis at {}", y), + Point { x, y } => println!("On neither axis: ({}, {})", x, y), + } +} +``` + +3. 🌟🌟🌟 + +```rust,editable + +// Remediați erorile +enum Message { + Hello { id: i32 }, +} + +fn main() { + let msg = Message::Hello { id: 5 }; + + match msg { + Message::Hello { + id: 3..=7, + } => println!("Found an id in range [3, 7]: {}", id), + Message::Hello { id: newid@10 | 11 | 12 } => { + println!("Found an id in another range [10, 12]: {}", newid) + } + Message::Hello { id } => println!("Found some other id: {}", id), + } +} +``` + +4. 🌟🌟 Un gard de potrivire este o condiție suplimentară specificată după model într-un braț de potrivire, care trebuie, de asemenea, să se potrivească, împreună cu potrivirea modelului, pentru ca acel braț să fie ales. +```rust,editable + +// Completați spațiile libere pentru a face codul să funcționeze, `split` TREBUIE să fie utilizat +fn main() { + let num = Some(4); + let split = 5; + match num { + Some(x) __ => assert!(x < split), + Some(x) => assert!(x >= split), + None => (), + } + + println!("Success!"); +} +``` + +5. 🌟🌟 Ignorarea părților rămase ale valorii cu `..` +```rust,editable + +// Completați spațiile libere pentru a face codul să funcționeze +fn main() { + let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048); + + match numbers { + __ => { + assert_eq!(first, 2); + assert_eq!(last, 2048); + } + } + + println!("Success!"); +} +``` + +6. 🌟🌟 Utilizarea modelului `&mut V` pentru a potrivi o referință mutabilă necesită foarte multă atenție, datorită faptului că `V` este o valoare după potrivire. + +```rust,editable + +// REMEDIAȚI eroarea cu cel mai mic număr de modificări +// NU eliminați nici o linie de cod +fn main() { + let mut v = String::from("hello,"); + let r = &mut v; + + match r { + &mut value => value.push_str(" world!") + } +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/result-panic/intro.md b/ro-RO/src/result-panic/intro.md new file mode 100644 index 000000000..4c0306ed7 --- /dev/null +++ b/ro-RO/src/result-panic/intro.md @@ -0,0 +1,5 @@ +# Result și Panic +Resurse de învățare: +- Engleză: [Rust Book 9.1, 9.2](https://doc.rust-lang.org/book/ch09-00-error-handling.html) +- Chineză simplificată: [Rust语言圣经 - 返回值和错误处理](https://course.rs/basic/result-error/intro.html) + diff --git a/ro-RO/src/result-panic/panic.md b/ro-RO/src/result-panic/panic.md new file mode 100644 index 000000000..97fc9efd9 --- /dev/null +++ b/ro-RO/src/result-panic/panic.md @@ -0,0 +1,113 @@ +# panic! +Cel mai simplu mecanism de gestionare a erorilor este să folosim panic. Aceasta doar afișează un mesaj de eroare și începe să deruleze stiva, în cele din urmă ieșind din thread-ul curent: + +- dacă panică apare în thread-ul main, atunci programul va fi închis. +- dacă apare într-un thread generat, atunci acel thread va fi terminat, dar programul nu va fi întrerupt. + + +1. 🌟🌟 +```rust,editable + +// UMPLI blank-urile +fn drink(beverage: &str) { + if beverage == "lemonade" { + println!("Success!"); + // IMPLEMENTEAZĂ codul de mai jos + __ + } + + println!("Exercise Failed if printing out this line!"); +} + +fn main() { + drink(__); + + println!("Exercise Failed if printing out this line!"); +} +``` + +## Cazuri comune de panică +2. 🌟🌟 +```rust,editable +// Faceți codul să funcționeze rezolvând toate panicele +fn main() { + assert_eq!("abc".as_bytes(), [96, 97, 98]); + + let v = vec![1, 2, 3]; + let ele = v[3]; + // "unwrap" poate genera panică când "get" returnează "None" + let ele = v.get(3).unwrap(); + + // Uneori, compilatorul nu poate găsi erorile de overflow pentru tine în timpul compilării, astfel că va apărea panică + let v = production_rate_per_hour(2); + + // din același motiv ca mai sus, trebuie să îl învelim într-o funcție pentru a provoca panică + divide(15, 0); + + println!("Success!") +} + +fn divide(x:u8, y:u8) { + println!("{}", x / y) +} + +fn production_rate_per_hour(speed: u8) -> f64 { + let cph: u8 = 221; + match speed { + 1..=4 => (speed * cph) as f64, + 5..=8 => (speed * cph) as f64 * 0.9, + 9..=10 => (speed * cph) as f64 * 0.77, + _ => 0 as f64, + } +} + +pub fn working_items_per_minute(speed: u8) -> u32 { + (production_rate_per_hour(speed) / 60 as f64) as u32 +} +``` + +### Stivă de apel detaliată +În mod implicit, derularea stivei va arăta ceva de genul: +```shell +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +``` + +Chiar dacă este indicat motivul panicii și linia de cod unde a avut loc panica, uneori vrem să obținem mai multe informații despre stiva de apel. + +3. 🌟 +```shell +## UMPLI blank-ul pentru a afișa întreaga stivă de apel +## Sugestie: poți găsi indicii în informațiile implicite despre panică +$ __ cargo run +thread 'main' panicked at 'assertion failed: `(left == right)` + left: `[97, 98, 99]`, + right: `[96, 97, 98]`', src/main.rs:3:5 +stack backtrace: + 0: rust_begin_unwind + at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/std/src/panicking.rs:498:5 + 1: core::panicking::panic_fmt + at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/panicking.rs:116:14 + 2: core::panicking::assert_failed_inner + 3: core::panicking::assert_failed + at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/panicking.rs:154:5 + 4: study_cargo::main + at ./src/main.rs:3:5 + 5: core::ops::function::FnOnce::call_once + at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ops/function.rs:227:5 +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. +``` + +### `unwinding` și `abort` +În mod implicit, atunci când apare o panic, programul începe să deruleze, ceea ce înseamnă că Rust se plimbă înapoi pe stivă și curăță datele din fiecare funcție întâlnită. + +Dar acest proces de parcurgere înapoi și de curățare este o muncă foarte mare. Alternativa este să întrerupem imediat programul fără a face curățenie. + +Dacă în proiectul tău ai nevoie să faci binarul rezultat cât mai mic posibil, poți trece de la derulare la întrerupere adăugând conținutul de mai jos în `Cargo.toml`: +```toml +[profile.release] +panic = 'abort' +``` + + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/result-panic/result.md b/ro-RO/src/result-panic/result.md new file mode 100644 index 000000000..2efd998e2 --- /dev/null +++ b/ro-RO/src/result-panic/result.md @@ -0,0 +1,213 @@ +# Result și ? +`Result` este o enumerare folosită pentru a descrie posibilele erori. Are două variante: + +- Ok(T): A fost găsită o valoare T +- Err(e): A fost găsită o eroare cu valoarea `e` +Pe scurt, rezultatul așteptat este `Ok`, în timp ce rezultatul neașteptat este `Err`. + +1. 🌟🌟 +```rust,editable + +// UMPLE blank-urile și REZOLVĂ erorile +use std::num::ParseIntError; + +fn multiply(n1_str: &str, n2_str: &str) -> __ { + let n1 = n1_str.parse::(); + let n2 = n2_str.parse::(); + Ok(n1.unwrap() * n2.unwrap()) +} + +fn main() { + let result = multiply("10", "2"); + assert_eq!(result, __); + + let result = multiply("t", "2"); + assert_eq!(result.__, 8); + + println!("Success!"); +} +``` + +### ? +`?` este aproape echivalent cu `unwrap`, dar `?` întoarce rezultatul în loc să provoace panică la `Err`. + +2. 🌟🌟 +```rust,editable + +use std::num::ParseIntError; + +// IMPLEMENTEAZĂ multiply cu ? +// NU folosi unwrap aici +fn multiply(n1_str: &str, n2_str: &str) -> __ { +} + +fn main() { + assert_eq!(multiply("3", "4").unwrap(), 12); + println!("Success!"); +} +``` + +3. 🌟🌟 +```rust,editable + +use std::fs::File; +use std::io::{self, Read}; + +fn read_file1() -> Result { + let f = File::open("hello.txt"); + let mut f = match f { + Ok(file) => file, + Err(e) => return Err(e), + }; + + let mut s = String::new(); + match f.read_to_string(&mut s) { + Ok(_) => Ok(s), + Err(e) => Err(e), + } +} + +// UMPLE blank-urile cu o linie de cod +// NU schimba nicio linie de cod +fn read_file2() -> Result { + let mut s = String::new(); + + __; + + Ok(s) +} + +fn main() { + assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string()); + println!("Success!"); +} +``` + +### map & and_then +[map](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.map) și [and_then](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.and_then) sunt doi combinatori comuni pentru `Result` (și pentru `Option`). + +4. 🌟🌟 + +```rust,editable +use std::num::ParseIntError; + +// UMPLE blank-ul în două moduri: map și and_then +fn add_two(n_str: &str) -> Result { + n_str.parse::().__ +} + +fn main() { + assert_eq!(add_two("4").unwrap(), 6); + + println!("Success!"); +} +``` + +5. 🌟🌟🌟 +```rust,editable +use std::num::ParseIntError; + +// Cu tipul returnat rescris, folosim potrivirea modelelor fără `unwrap()`. +// Dar este atât de detaliat... +fn multiply(n1_str: &str, n2_str: &str) -> Result { + match n1_str.parse::() { + Ok(n1) => { + match n2_str.parse::() { + Ok(n2) => { + Ok(n1 * n2) + }, + Err(e) => Err(e), + } + }, + Err(e) => Err(e), + } +} + +// Rescrierea `multiply` pentru a o face concisă +// Ar trebui să folosești ATÂT `and_then` cât și `map` aici. +fn multiply1(n1_str: &str, n2_str: &str) -> Result { + // IMPLEMENTEAZĂ... +} + +fn print(result: Result) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + // Aceasta oferă încă un răspuns rezonabil. + let twenty = multiply1("10", "2"); + print(twenty); + + // Următorul oferă acum un mesaj de eroare mult mai util. + let tt = multiply("t", "2"); + print(tt); + + println!("Success!"); +} +``` + +### Alias de tipuri +Folosirea `std::result::Result` peste tot este stufos și plictisitor, putem folosi un alias în acest scop. + +La nivel de modul, crearea de aliasuri poate fi deosebit de utilă. Erorile găsite într-un modul specific au adesea același tip `Err`, astfel că un singur alias poate defini concis toate `Result`-urile asociate. Aceasta este atât de utilă încât biblioteca standard furnizează una: [`io::Result`](https://doc.rust-lang.org/std/io/type.Result.html). + +6. 🌟 +```rust,editable +use std::num::ParseIntError; + +// UMPLE blank-ul +type __; + +// Folosește aliasul de mai sus pentru a te referi la tipul nostru specific `Result`. +fn multiply(first_number_str: &str, second_number_str: &str) -> Res { + first_number_str.parse::().and_then(|first_number| { + second_number_str.parse::().map(|second_number| first_number * second_number) + }) +} + +// Aici, aliasul permite din nou să economisim spațiu. +fn print(result: Res) { + match result { + Ok(n) => println!("n is {}", n), + Err(e) => println!("Error: {}", e), + } +} + +fn main() { + print(multiply("10", "2")); + print(multiply("t", "2")); + + println!("Success!"); +} +``` + +### Utilizarea Result în `fn main` +De obicei, funcția `main` va arăta așa: +```rust +fn main() { + println!("Hello World!"); +} +``` + +Cu toate acestea, main poate avea și un tip de returnare `Result`. Dacă apare o eroare în cadrul funcției `main`, aceasta va returna un cod de eroare și va imprima o reprezentare de depanare a erorii (traitul Debug). + +Următorul exemplu arată o astfel de situație: +```rust,editable + +use std::num::ParseIntError; + +fn main() -> Result<(), ParseIntError> { + let number_str = "10"; + let number = match number_str.parse::() { + Ok(number) => number, + Err(e) => return Err(e), + }; + println!("{}", number); + Ok(()) +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/self-referential.md b/ro-RO/src/self-referential.md new file mode 100644 index 000000000..37a478447 --- /dev/null +++ b/ro-RO/src/self-referential.md @@ -0,0 +1 @@ +# Self referential diff --git a/ro-RO/src/smart-pointers/box.md b/ro-RO/src/smart-pointers/box.md new file mode 100644 index 000000000..2436f01e6 --- /dev/null +++ b/ro-RO/src/smart-pointers/box.md @@ -0,0 +1 @@ +# Box diff --git a/ro-RO/src/smart-pointers/cell-refcell.md b/ro-RO/src/smart-pointers/cell-refcell.md new file mode 100644 index 000000000..4e61a02b5 --- /dev/null +++ b/ro-RO/src/smart-pointers/cell-refcell.md @@ -0,0 +1 @@ +# Cell and RefCell diff --git a/ro-RO/src/smart-pointers/deref.md b/ro-RO/src/smart-pointers/deref.md new file mode 100644 index 000000000..8c709e8d4 --- /dev/null +++ b/ro-RO/src/smart-pointers/deref.md @@ -0,0 +1 @@ +# Deref diff --git a/ro-RO/src/smart-pointers/drop.md b/ro-RO/src/smart-pointers/drop.md new file mode 100644 index 000000000..c6ecf823e --- /dev/null +++ b/ro-RO/src/smart-pointers/drop.md @@ -0,0 +1 @@ +# Drop diff --git a/ro-RO/src/smart-pointers/intro.md b/ro-RO/src/smart-pointers/intro.md new file mode 100644 index 000000000..37c40cefc --- /dev/null +++ b/ro-RO/src/smart-pointers/intro.md @@ -0,0 +1,3 @@ +# Smart pointers + + \ No newline at end of file diff --git a/ro-RO/src/smart-pointers/rc-arc.md b/ro-RO/src/smart-pointers/rc-arc.md new file mode 100644 index 000000000..8f723ed35 --- /dev/null +++ b/ro-RO/src/smart-pointers/rc-arc.md @@ -0,0 +1 @@ +# Rc and Arc diff --git a/ro-RO/src/std/String.md b/ro-RO/src/std/String.md new file mode 100644 index 000000000..2c0923c4d --- /dev/null +++ b/ro-RO/src/std/String.md @@ -0,0 +1 @@ +# String diff --git a/ro-RO/src/std/intro.md b/ro-RO/src/std/intro.md new file mode 100644 index 000000000..c6d43326d --- /dev/null +++ b/ro-RO/src/std/intro.md @@ -0,0 +1 @@ +# Stand Library todo diff --git a/ro-RO/src/tests/assertions.md b/ro-RO/src/tests/assertions.md new file mode 100644 index 000000000..f5743ab7b --- /dev/null +++ b/ro-RO/src/tests/assertions.md @@ -0,0 +1 @@ +# Assertions diff --git a/ro-RO/src/tests/benchmark.md b/ro-RO/src/tests/benchmark.md new file mode 100644 index 000000000..f883201d5 --- /dev/null +++ b/ro-RO/src/tests/benchmark.md @@ -0,0 +1,3 @@ +# Benchmark + +https://doc.rust-lang.org/unstable-book/library-features/test.html \ No newline at end of file diff --git a/ro-RO/src/tests/intro.md b/ro-RO/src/tests/intro.md new file mode 100644 index 000000000..007eb9551 --- /dev/null +++ b/ro-RO/src/tests/intro.md @@ -0,0 +1 @@ +# Tests diff --git a/ro-RO/src/tests/unit-integration.md b/ro-RO/src/tests/unit-integration.md new file mode 100644 index 000000000..68df7e425 --- /dev/null +++ b/ro-RO/src/tests/unit-integration.md @@ -0,0 +1 @@ +# Unit and Integration diff --git a/ro-RO/src/tests/write-tests.md b/ro-RO/src/tests/write-tests.md new file mode 100644 index 000000000..245c70190 --- /dev/null +++ b/ro-RO/src/tests/write-tests.md @@ -0,0 +1 @@ +# Write Tests diff --git a/ro-RO/src/threads/atomic.md b/ro-RO/src/threads/atomic.md new file mode 100644 index 000000000..eecfaa885 --- /dev/null +++ b/ro-RO/src/threads/atomic.md @@ -0,0 +1 @@ +# Atomic diff --git a/ro-RO/src/threads/basic-using.md b/ro-RO/src/threads/basic-using.md new file mode 100644 index 000000000..f0a2d4683 --- /dev/null +++ b/ro-RO/src/threads/basic-using.md @@ -0,0 +1 @@ +# Basic using diff --git a/ro-RO/src/threads/intro.md b/ro-RO/src/threads/intro.md new file mode 100644 index 000000000..f60f3991e --- /dev/null +++ b/ro-RO/src/threads/intro.md @@ -0,0 +1 @@ +# Threads diff --git a/ro-RO/src/threads/message-passing.md b/ro-RO/src/threads/message-passing.md new file mode 100644 index 000000000..4d33941e7 --- /dev/null +++ b/ro-RO/src/threads/message-passing.md @@ -0,0 +1 @@ +# Message passing diff --git a/ro-RO/src/threads/send-sync.md b/ro-RO/src/threads/send-sync.md new file mode 100644 index 000000000..171f95f11 --- /dev/null +++ b/ro-RO/src/threads/send-sync.md @@ -0,0 +1 @@ +# Send and Sync diff --git a/ro-RO/src/threads/sync.md b/ro-RO/src/threads/sync.md new file mode 100644 index 000000000..bc4491e8e --- /dev/null +++ b/ro-RO/src/threads/sync.md @@ -0,0 +1 @@ +# Sync diff --git a/ro-RO/src/type-conversions/as.md b/ro-RO/src/type-conversions/as.md new file mode 100644 index 000000000..d2896dec9 --- /dev/null +++ b/ro-RO/src/type-conversions/as.md @@ -0,0 +1,107 @@ +# Conversie prin `as` +În limbajul Rust, nu există conversie implicită de tip (coerciție) între tipurile de bază. Cu toate acestea, conversiile explicite de tip pot fi realizate folosind cuvântul cheie `as`. + +1. 🌟 +```rust,editable +// CORECTAȚI erorile și completați spațiile goale +// NU eliminați niciun cod +fn main() { + let decimal = 97.123_f32; + + let integer: __ = decimal as u8; + + let c1: char = decimal as char; + let c2 = integer as char; + + assert_eq!(integer, 'b' as u8); + + println!("Success!"); +} +``` + +2. 🌟🌟 Implicit, depășirea valorilor maxime va provoca erori de compilare, dar putem adăuga o adnotare globală pentru a suprima aceste erori. +```rust,editable +fn main() { + assert_eq!(u8::MAX, 255); + // Maximul pentru `u8` este 255, conform afirmației anterioare. + // Prin urmare, codul de mai jos va provoca o eroare de depășire: litera în afara intervalului pentru `u8`. + // VA ROG să căutați indicii în erorile de compilare pentru a CORECTA aceasta. + // NU modificați niciun cod în main. + let v = 1000 as u8; + + println!("Success!"); +} +``` + +3. 🌟🌟 La conversia oricărei valori la un tip nesemnat `T`, se adaugă sau se scade `T::MAX + 1` până când valoarea se potrivește în noul tip. +```rust,editable +fn main() { + assert_eq!(1000 as u16, __); + + assert_eq!(1000 as u8, __); + + // Pentru numerele pozitive, acest lucru este echivalent cu modulo + println!("1000 mod 256 is : {}", 1000 % 256); + + assert_eq!(-1_i8 as u8, __); + + // Începând cu Rust 1.45, cuvântul cheie `as` efectuează o *conversie cu săturare* + // atunci când se face conversia de la float la int. Dacă valoarea cu virgulă depășește + // limita superioară sau este mai mică decât limita inferioară, valoarea returnată + // va fi egală cu limita depășită. + assert_eq!(300.1_f32 as u8, __); + assert_eq!(-100.1_f32 as u8, __); + + + // Această comportare implică un cost mic la runtime și poate fi evitată + // cu metode nesigure, totuși rezultatele ar putea depăși și returna **valori nesigure**. + /* Use these methods wisely: */ + unsafe { + // 300.0 este 44 + println!("300.0 is {}", 300.0_f32.to_int_unchecked::()); + // -100.0 ca u8 este 156 + println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::()); + // nan ca u8 este 0 + println!("nan as u8 is {}", f32::NAN.to_int_unchecked::()); + } +} +``` + +4. 🌟🌟🌟 Pointerii raw pot fi convertiți la adrese de memorie (integer) și invers. +```rust,editable + +// Completați spațiile goale +fn main() { + let mut values: [i32; 2] = [1, 2]; + let p1: *mut i32 = values.as_mut_ptr(); + let first_address: usize = p1 __; + let second_address = first_address + 4; // 4 == std::mem::size_of::() + let p2: *mut i32 = second_address __; // p2 indică către al doilea element în values + unsafe { + // Adăugați unu la al doilea element + __ + } + + assert_eq!(values[1], 3); + + println!("Success!"); +} +``` + + +5. 🌟🌟🌟 +```rust,editable +fn main() { + let arr :[u64; 13] = [0; 13]; + assert_eq!(std::mem::size_of_val(&arr), 8 * 13); + let a: *const [u64] = &arr; + let b = a as *const [u8]; + unsafe { + assert_eq!(std::mem::size_of_val(&*b), __) + } + + println!("Success!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) \ No newline at end of file diff --git a/ro-RO/src/type-conversions/from-into.md b/ro-RO/src/type-conversions/from-into.md new file mode 100644 index 000000000..f0283ed54 --- /dev/null +++ b/ro-RO/src/type-conversions/from-into.md @@ -0,0 +1,169 @@ +# From/Into +Trait-ul `From` permite unui tip să definească modul în care se poate crea singur dintr-un alt tip, oferind astfel o modalitate foarte simplă de a converti între mai multe tipuri. + +Trait-urile `From` și `Into` sunt intrinsec legate, și acest lucru face parte din implementarea lor. Acest lucru înseamnă că dacă scriem ceva de genul: `impl From` pentru U, atunci putem utiliza let u: `U = U::from(T)` sau `let u:U = T.into()`. + +Trait-ul Into este pur și simplu reciprocul trait-ului `From`. Adică, dacă ați implementat trait-ul `From` pentru tipul vostru, atunci trait-ul `Into` va fi implementat automat pentru același tip. + +Utilizarea trait-ului `Into` va necesita în mod tipic adnotările de tip, deoarece compilatorul nu poate determina acest lucru de cele mai multe ori. + +De exemplu, putem converti ușor `&str` în `String`: +```rust +fn main() { + let my_str = "hello"; + + // cele trei conversii de mai jos depind toate de faptul că String implementează From<&str>: + let string1 = String::from(my_str); + let string2 = my_str.to_string(); + // Este necesară adnotarea explicită de tip aici + let string3: String = my_str.into(); +} +``` + +Deoarece biblioteca standard a implementat deja acest lucru pentru noi: `impl From<&'_ str>` pentru String. + +Unele implementări ale trait-ului `From` pot fi găsite [aici](https://doc.rust-lang.org/stable/std/convert/trait.From.html#implementors). + +1. 🌟🌟🌟 +```rust,editable +fn main() { + // impl From pentru i32 + let i1: i32 = false.into(); + let i2: i32 = i32::from(false); + assert_eq!(i1, i2); + assert_eq!(i1, 0); + + // CORECTAȚI eroarea în două moduri + /* 1. utilizați un tip similar care `impl From`, poate ar trebui să verificați documentația menționată mai sus pentru a găsi răspunsul */ + // 2. un cuvânt cheie din ultimul capitol + let i3: i32 = 'a'.into(); + + // CORECTAȚI eroarea în două moduri + let s: String = 'a' as String; + + println!("Success!"); +} +``` + +### Implementare `From` pentru tipuri personalizate +2. 🌟🌟 +```rust,editable +// `From` este acum inclus în `std::prelude`, deci nu este nevoie să-l introducem în domeniul de vizibilitate actual +// use std::convert::From; + +#[derive(Debug)] +struct Number { + value: i32, +} + +impl From for Number { + // IMPLEMENTAȚI metoda `from` +} + +// COMPLETAȚI spațiile goale +fn main() { + let num = __(30); + assert_eq!(num.value, 30); + + let num: Number = __; + assert_eq!(num.value, 30); + + println!("Success!"); +} +``` + +3. 🌟🌟🌟 Când efectuăm gestionarea erorilor, este adesea util să implementăm trait-ul From pentru propria noastră eroare. Atunci putem utiliza ? pentru a converti automat tipul de eroare subiacent la propria noastră eroare. +```rust,editable +use std::fs; +use std::io; +use std::num; + +enum CliError { + IoError(io::Error), + ParseError(num::ParseIntError), +} + +impl From for CliError { + // IMPLEMENTAȚI metoda `from` +} + +impl From for CliError { + // IMPLEMENTAȚI metoda `from` +} + +fn open_and_parse_file(file_name: &str) -> Result { + // ? convertește automat io::Error la CliError + let contents = fs::read_to_string(&file_name)?; + // num::ParseIntError -> CliError + let num: i32 = contents.trim().parse()?; + Ok(num) +} + +fn main() { + println!("Success!"); +} +``` + + +### TryFrom/TryInto +Similar cu `From` și `Into`, `TryFrom` și `TryInto` sunt trait-uri generice pentru conversii între tipuri. + +Spre deosebire de `From/Into`, `TryFrom` și `TryInto` sunt folosite pentru conversiile care pot eșua și returnează un Result în loc de o valoare simplă. + +4. 🌟🌟 +```rust,editable +// TryFrom și TryInto sunt incluse în `std::prelude`, deci nu este nevoie să le introducem în domeniul de vizibilitate actual +// use std::convert::TryInto; + +fn main() { + let n: i16 = 256; + + // Trait-ul Into are o metodă `into`, + // prin urmare TryInto are o metodă ? + let n: u8 = match n.__() { + Ok(n) => n, + Err(e) => { + println!("there is an error when converting: {:?}, but we catch it", e.to_string()); + 0 + } + }; + + assert_eq!(n, __); + + println!("Success!"); +} +``` + +5. 🌟🌟🌟 +```rust,editable +#[derive(Debug, PartialEq)] +struct EvenNum(i32); + +impl TryFrom for EvenNum { + type Error = (); + + // IMPLEMENTAȚI `try_from` + fn try_from(value: i32) -> Result { + if value % 2 == 0 { + Ok(EvenNum(value)) + } else { + Err(()) + } + } +} + +fn main() { + assert_eq!(EvenNum::try_from(8), Ok(EvenNum(8))); + assert_eq!(EvenNum::try_from(5), Err(())); + + // COMPLETAȚI spațiile goale + let result: Result = 8i32.try_into(); + assert_eq!(result, __); + let result: Result = 5i32.try_into(); + assert_eq!(result, __); + + println!("Success!"); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/type-conversions/intro.md b/ro-RO/src/type-conversions/intro.md new file mode 100644 index 000000000..82d3fc9f4 --- /dev/null +++ b/ro-RO/src/type-conversions/intro.md @@ -0,0 +1,5 @@ +# Conversia de Tipuri +Resurse de învățare: +- Engleză: [Standary library](https://std.rs) +- Chineză simplificată: [Rust语言圣经 - 所有权与借用](https://course.rs/basic/converse.html) + diff --git a/ro-RO/src/type-conversions/others.md b/ro-RO/src/type-conversions/others.md new file mode 100644 index 000000000..c549b07ee --- /dev/null +++ b/ro-RO/src/type-conversions/others.md @@ -0,0 +1,169 @@ +# Altele + +### Conversia oricărui tip în șir de caractere (String) + +Pentru a converti orice tip în `String`, puteți folosi pur și simplu trait-ul `ToString` pentru acel tip. În loc să faceți asta direct, ar trebui să implementați trait-ul `fmt::Display`, care va oferi automat și `ToString` și vă permite să afișați tipul cu `println!`. + +1. 🌟🌟 +```rust,editable +use std::fmt; + +struct Point { + x: i32, + y: i32, +} + +impl fmt::Display for Point { + // IMPLEMENTAȚI metoda fmt +} + +fn main() { + let origin = Point { x: 0, y: 0 }; + // COMPLETAȚI spațiile goale + assert_eq!(origin.__, "The point is (0, 0)"); + assert_eq!(format!(__), "The point is (0, 0)"); + + println!("Success!"); +} +``` + +### Parsarea unui șir de caractere (String) +2. 🌟🌟🌟 Putem folosi metoda `parse` pentru a converti un număr `i32` dintr-un șir de caractere (`String`), acest lucru se datorează faptului că `FromStr` este implementat pentru tipul `i32` în biblioteca standard: `impl FromStr for i32` +```rust,editable +// Pentru a utiliza metoda `from_str`, trebuie să introduceți acest trait în domeniul de vizibilitate curent. +use std::str::FromStr; +fn main() { + let parsed: i32 = "5".__.unwrap(); + let turbo_parsed = "10".__.unwrap(); + let from_str = __.unwrap(); + let sum = parsed + turbo_parsed + from_str; + assert_eq!(sum, 35); + + println!("Success!"); +} +``` + + +3. 🌟🌟 Putem, de asemenea, să implementăm trait-ul `FromStr` pentru tipurile noastre personalizate +```rust,editable +use std::str::FromStr; +use std::num::ParseIntError; + +#[derive(Debug, PartialEq)] +struct Point { + x: i32, + y: i32 +} + +impl FromStr for Point { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) + .split(',') + .map(|x| x.trim()) + .collect(); + + let x_fromstr = coords[0].parse::()?; + let y_fromstr = coords[1].parse::()?; + + Ok(Point { x: x_fromstr, y: y_fromstr }) + } +} +fn main() { + // COMPLETAȚI spațiile goale în două moduri + // NU schimbați codul în niciun alt loc + let p = __; + assert_eq!(p.unwrap(), Point{ x: 3, y: 4} ); + + println!("Success!"); +} +``` + +### Deref +You can find all the examples and exercises of the `Deref` trait [here](https://practice.rs/smart-pointers/deref.html). + +### Transmute +**`std::mem::transmute`** este o **funcție nesigură** care poate fi folosită pentru a reinterpreta biții unei valori de un tip ca fiind de alt tip. Ambele tipuri original și rezultat trebuie să aibă aceeași dimensiune și niciunul dintre ele nu poate fi nevalid. + +**`transmute`** este echivalent semantic cu o mutare pe biți a unei valori din sursă în destinație. Copiază biții din valoarea sursă în valoarea destinație, apoi uită originalul, părând a fi echivalent cu memcpy din C sub capotă. + +Așadar, **`transmute` este incredibil de nesigură!** Cel care o apelează trebuie să se asigure singur de toate aspectele de siguranță! + +### Exemple +`transmute` poate fi folosită pentru a transforma un pointer într-un pointer la o funcție, acest lucru nu este portabil pe mașini în care pointer-ul la funcție și pointer-ul la date au dimensiuni diferite. + +```rust,editable +fn foo() -> i32 { + 0 +} + +fn main() { + let pointer = foo as *const (); + let function = unsafe { + std::mem::transmute::<*const (), fn() -> i32>(pointer) + }; + assert_eq!(function(), 0); +} +``` + +2. Extinderea unei perioade de valabilitate (lifetime) sau scurtarea unei perioade de valabilitate a unei invariante este o utilizare avansată a `transmute`. +```rust,editable +struct R<'a>(&'a i32); +unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + std::mem::transmute::, R<'static>>(r) +} + +unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + -> &'b mut R<'c> { + std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) +} +``` + +3. În loc să folosiți `transmute`, puteți utiliza unele alternative în schimb. +```rust,editable +fn main() { + /*Transformarea de biți bruti (&[u8]) în u32, f64, etc.: */ + let raw_bytes = [0x78, 0x56, 0x34, 0x12]; + + let num = unsafe { std::mem::transmute::<[u8; 4], u32>(raw_bytes) }; + + // Folosiți `u32::from_ne_bytes` în schimb + let num = u32::from_ne_bytes(raw_bytes); + // Sau folosiți `u32::from_le_bytes` sau `u32::from_be_bytes` pentru a specifica endianitatea + let num = u32::from_le_bytes(raw_bytes); + assert_eq!(num, 0x12345678); + let num = u32::from_be_bytes(raw_bytes); + assert_eq!(num, 0x78563412); + + /*Transformarea unui pointer într-un usize: */ + let ptr = &0; + let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr) }; + + // Folosiți o conversie `as` în schimb + let ptr_num_cast = ptr as *const i32 as usize; + + /*Transformarea unui &mut T într-un &mut U: */ + let ptr = &mut 0; + let val_transmuted = unsafe { std::mem::transmute::<&mut i32, &mut u32>(ptr) }; + + // Acum, combinați `as` și reîmprumutați - observați concatenarea `as` + // `as` nu este tranzitiv + let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; + + /*Transformarea unui &str într-un &[u8]: */ + // Aceasta nu este o modalitate bună de a face acest lucru. + let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; + assert_eq!(slice, &[82, 117, 115, 116]); + + // Ați putea folosi `str::as_bytes` + let slice = "Rust".as_bytes(); + assert_eq!(slice, &[82, 117, 115, 116]); + + // Sau, pur și simplu, utilizați un șir de octeți, dacă + // aveți control asupra literalului de șir + assert_eq!(b"Rust", &[82, 117, 115, 116]); +} +``` + +> Puteți găsi soluțiile [aici](https://github.com/sunface/rust-by-practice) (în cadrul căii soluțiilor), dar folosiți-le doar atunci când aveți nevoie. :) diff --git a/ro-RO/src/unsafe/inline-asm.md b/ro-RO/src/unsafe/inline-asm.md new file mode 100644 index 000000000..2a007ca85 --- /dev/null +++ b/ro-RO/src/unsafe/inline-asm.md @@ -0,0 +1,441 @@ +# Inline assembly + +Rust provides support for inline assembly via the `asm!` macro. +It can be used to embed handwritten assembly in the assembly output generated by the compiler. +Generally this should not be necessary, but might be where the required performance or timing +cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality. + +> **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported. + +Inline assembly is currently supported on the following architectures: +- x86 and x86-64 +- ARM +- AArch64 +- RISC-V + +## Basic usage + +Let us start with the simplest possible example: + +```rust +use std::arch::asm; + +unsafe { + asm!("nop"); +} +``` + +This will insert a NOP (no operation) instruction into the assembly generated by the compiler. +Note that all `asm!` invocations have to be inside an `unsafe` block, as they could insert +arbitrary instructions and break various invariants. The instructions to be inserted are listed +in the first argument of the `asm!` macro as a string literal. + +## Inputs and outputs + +Now inserting an instruction that does nothing is rather boring. Let us do something that +actually acts on data: + +```rust +use std::arch::asm; + +let x: u64; +unsafe { + asm!("mov {}, 5", out(reg) x); +} +assert_eq!(x, 5); +``` + +This will write the value `5` into the `u64` variable `x`. +You can see that the string literal we use to specify instructions is actually a template string. +It is governed by the same rules as Rust [format strings][format-syntax]. +The arguments that are inserted into the template however look a bit different than you may +be familiar with. First we need to specify if the variable is an input or an output of the +inline assembly. In this case it is an output. We declared this by writing `out`. +We also need to specify in what kind of register the assembly expects the variable. +In this case we put it in an arbitrary general purpose register by specifying `reg`. +The compiler will choose an appropriate register to insert into +the template and will read the variable from there after the inline assembly finishes executing. + +[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax + +Let us see another example that also uses an input: + +```rust +use std::arch::asm; + +let i: u64 = 3; +let o: u64; +unsafe { + asm!( + "mov {0}, {1}", + "add {0}, 5", + out(reg) o, + in(reg) i, + ); +} +assert_eq!(o, 8); +``` + +This will add `5` to the input in variable `i` and write the result to variable `o`. +The particular way this assembly does this is first copying the value from `i` to the output, +and then adding `5` to it. + +The example shows a few things: + +First, we can see that `asm!` allows multiple template string arguments; each +one is treated as a separate line of assembly code, as if they were all joined +together with newlines between them. This makes it easy to format assembly +code. + +Second, we can see that inputs are declared by writing `in` instead of `out`. + +Third, we can see that we can specify an argument number, or name as in any format string. +For inline assembly templates this is particularly useful as arguments are often used more than once. +For more complex inline assembly using this facility is generally recommended, as it improves +readability, and allows reordering instructions without changing the argument order. + +We can further refine the above example to avoid the `mov` instruction: + +```rust +use std::arch::asm; + +let mut x: u64 = 3; +unsafe { + asm!("add {0}, 5", inout(reg) x); +} +assert_eq!(x, 8); +``` + +We can see that `inout` is used to specify an argument that is both input and output. +This is different from specifying an input and output separately in that it is guaranteed to assign both to the same register. + +It is also possible to specify different variables for the input and output parts of an `inout` operand: + +```rust +use std::arch::asm; + +let x: u64 = 3; +let y: u64; +unsafe { + asm!("add {0}, 5", inout(reg) x => y); +} +assert_eq!(y, 8); +``` + +## Late output operands + +The Rust compiler is conservative with its allocation of operands. It is assumed that an `out` +can be written at any time, and can therefore not share its location with any other argument. +However, to guarantee optimal performance it is important to use as few registers as possible, +so they won't have to be saved and reloaded around the inline assembly block. +To achieve this Rust provides a `lateout` specifier. This can be used on any output that is +written only after all inputs have been consumed. +There is also a `inlateout` variant of this specifier. + +Here is an example where `inlateout` *cannot* be used: + +```rust +use std::arch::asm; + +let mut a: u64 = 4; +let b: u64 = 4; +let c: u64 = 4; +unsafe { + asm!( + "add {0}, {1}", + "add {0}, {2}", + inout(reg) a, + in(reg) b, + in(reg) c, + ); +} +assert_eq!(a, 12); +``` + +Here the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result. + +However the following example can use `inlateout` since the output is only modified after all input registers have been read: + +```rust +use std::arch::asm; + +let mut a: u64 = 4; +let b: u64 = 4; +unsafe { + asm!("add {0}, {1}", inlateout(reg) a, in(reg) b); +} +assert_eq!(a, 8); +``` + +As you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register. + +## Explicit register operands + +Some instructions require that the operands be in a specific register. +Therefore, Rust inline assembly provides some more specific constraint specifiers. +While `reg` is generally available on any architecture, explicit registers are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi` among others can be addressed by their name. + +```rust,no_run +use std::arch::asm; + +let cmd = 0xd1; +unsafe { + asm!("out 0x64, eax", in("eax") cmd); +} +``` + +In this example we call the `out` instruction to output the content of the `cmd` variable to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand we had to use the `eax` constraint specifier. + +> **Note**: unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types. + +Consider this example which uses the x86 `mul` instruction: + +```rust +use std::arch::asm; + +fn mul(a: u64, b: u64) -> u128 { + let lo: u64; + let hi: u64; + + unsafe { + asm!( + // The x86 mul instruction takes rax as an implicit input and writes + // the 128-bit result of the multiplication to rax:rdx. + "mul {}", + in(reg) a, + inlateout("rax") b => lo, + lateout("rdx") hi + ); + } + + ((hi as u128) << 64) + lo as u128 +} +``` + +This uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result. +The only explicit operand is a register, that we fill from the variable `a`. +The second operand is implicit, and must be the `rax` register, which we fill from the variable `b`. +The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`. +The higher 64 bits are stored in `rdx` from which we fill the variable `hi`. + +## Clobbered registers + +In many cases inline assembly will modify state that is not needed as an output. +Usually this is either because we have to use a scratch register in the assembly or because instructions modify state that we don't need to further examine. +This state is generally referred to as being "clobbered". +We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block. + +```rust +use core::arch::asm; + +fn main() { + // three entries of four bytes each + let mut name_buf = [0_u8; 12]; + // String is stored as ascii in ebx, edx, ecx in order + // Because ebx is reserved, we get a scratch register and move from + // ebx into it in the asm. The asm needs to preserve the value of + // that register though, so it is pushed and popped around the main asm + // (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx) + + unsafe { + asm!( + "push rbx", + "cpuid", + "mov [{0}], ebx", + "mov [{0} + 4], edx", + "mov [{0} + 8], ecx", + "pop rbx", + // We use a pointer to an array for storing the values to simplify + // the Rust code at the cost of a couple more asm instructions + // This is more explicit with how the asm works however, as opposed + // to explicit register outputs such as `out("ecx") val` + // The *pointer itself* is only an input even though it's written behind + in(reg) name_buf.as_mut_ptr(), + // select cpuid 0, also specify eax as clobbered + inout("eax") 0 => _, + // cpuid clobbers these registers too + out("ecx") _, + out("edx") _, + ); + } + + let name = core::str::from_utf8(&name_buf).unwrap(); + println!("CPU Manufacturer ID: {}", name); +} +``` + +In the example above we use the `cpuid` instruction to read the CPU manufacturer ID. +This instruction writes to `eax` with the maximum supported `cpuid` argument and `ebx`, `esx`, and `ecx` with the CPU manufacturer ID as ASCII bytes in that order. + +Even though `eax` is never read we still need to tell the compiler that the register has been modified so that the compiler can save any values that were in these registers before the asm. This is done by declaring it as an output but with `_` instead of a variable name, which indicates that the output value is to be discarded. + +This code also works around the limitation that `ebx` is a reserved register by LLVM. That means that LLVM assumes that it has full control over the register and it must be restored to its original state before exiting the asm block, so it cannot be used as an output. To work around this we save the register via `push`, read from `ebx` inside the asm block into a temporary register allocated with `out(reg)` and then restoring `ebx` to its original state via `pop`. The `push` and `pop` use the full 64-bit `rbx` version of the register to ensure that the entire register is saved. On 32 bit targets the code would instead use `ebx` in the `push`/`pop`. + +This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code: + +```rust +use std::arch::asm; + +// Multiply x by 6 using shifts and adds +let mut x: u64 = 4; +unsafe { + asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); +} +assert_eq!(x, 4 * 6); +``` + +## Symbol operands and ABI clobbers + +By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`] argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted. + +[`clobber_abi`]: ../../reference/inline-assembly.html#abi-clobbers + +```rust +use std::arch::asm; + +extern "C" fn foo(arg: i32) -> i32 { + println!("arg = {}", arg); + arg * 2 +} + +fn call_foo(arg: i32) -> i32 { + unsafe { + let result; + asm!( + "call *{}", + // Function pointer to call + in(reg) foo, + // 1st argument in rdi + in("rdi") arg, + // Return value in rax + out("rax") result, + // Mark all registers which are not preserved by the "C" calling + // convention as clobbered. + clobber_abi("C"), + ); + result + } +} +``` + +## Register template modifiers + +In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register). + +By default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc). + +This default can be overridden by using modifiers on the template string operands, just like you would with format strings: + +```rust +use std::arch::asm; + +let mut x: u16 = 0xab; + +unsafe { + asm!("mov {0:h}, {0:l}", inout(reg_abcd) x); +} + +assert_eq!(x, 0xabab); +``` + +In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 registers (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently. + +Let us assume that the register allocator has chosen to allocate `x` in the `ax` register. +The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte. + +If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use. + +## Memory address operands + +Sometimes assembly instructions require operands passed via memory addresses/memory locations. +You have to manually use the memory address syntax specified by the target architecture. +For example, on x86/x86_64 using Intel assembly syntax, you should wrap inputs/outputs in `[]` to indicate they are memory operands: + +```rust +use std::arch::asm; + +fn load_fpu_control_word(control: u16) { + unsafe { + asm!("fldcw [{}]", in(reg) &control, options(nostack)); + } +} +``` + +## Labels + +Any reuse of a named label, local or otherwise, can result in an assembler or linker error or may cause other strange behavior. Reuse of a named label can happen in a variety of ways including: + +- explicitly: using a label more than once in one `asm!` block, or multiple times across blocks. +- implicitly via inlining: the compiler is allowed to instantiate multiple copies of an `asm!` block, for example when the function containing it is inlined in multiple places. +- implicitly via LTO: LTO can cause code from *other crates* to be placed in the same codegen unit, and so could bring in arbitrary labels. + +As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions. + +Moreover, on x86 when using the default Intel syntax, due to [an LLVM bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. (See [Options](#options), below, for more on `options`.) + +```rust +use std::arch::asm; + +let mut a = 0; +unsafe { + asm!( + "mov {0}, 10", + "2:", + "sub {0}, 1", + "cmp {0}, 3", + "jle 2f", + "jmp 2b", + "2:", + "add {0}, 2", + out(reg) a + ); +} +assert_eq!(a, 5); +``` + +This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`. + +This example shows a few things: + +- First, that the same number can be used as a label multiple times in the same inline block. +- Second, that when a numeric label is used as a reference (as an instruction operand, for example), the suffixes “b” (“backward”) or ”f” (“forward”) should be added to the numeric label. It will then refer to the nearest label defined by this number in this direction. + +[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels +[an LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 + +## Options + +By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However, in many cases it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better. + +Let's take our previous example of an `add` instruction: + +```rust +use std::arch::asm; + +let mut a: u64 = 4; +let b: u64 = 4; +unsafe { + asm!( + "add {0}, {1}", + inlateout(reg) a, in(reg) b, + options(pure, nomem, nostack), + ); +} +assert_eq!(a, 8); +``` + +Options can be provided as an optional final argument to the `asm!` macro. We specified three options here: +- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely. +- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global). +- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments. + +These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed. + +See the [reference](../../reference/inline-assembly.html) for the full list of available options and their effects. \ No newline at end of file diff --git a/ro-RO/src/unsafe/intro.md b/ro-RO/src/unsafe/intro.md new file mode 100644 index 000000000..0597b958b --- /dev/null +++ b/ro-RO/src/unsafe/intro.md @@ -0,0 +1 @@ +# Unsafe todo diff --git a/ro-RO/src/variables.md b/ro-RO/src/variables.md new file mode 100644 index 000000000..527062d5b --- /dev/null +++ b/ro-RO/src/variables.md @@ -0,0 +1,158 @@ +# Variables + +### Binding and mutability +1. 🌟 A variable can be used only if it has been initialized. +```rust,editable + +// Fix the error below with least amount of modification to the code +fn main() { + let x: i32; // Uninitialized but used, ERROR ! + let y: i32; // Uninitialized but also unused, only a Warning ! + + assert_eq!(x, 5); + println!("Success!"); +} +``` + +2. 🌟 Use `mut` to mark a variable as mutable. +```rust,editable + +// Fill the blanks in the code to make it compile +fn main() { + let __ __ = 1; + __ += 2; + + assert_eq!(x, 3); + println!("Success!"); +} +``` + +### Scope +A scope is the range within the program for which the item is valid. + +3. 🌟 +```rust,editable + +// Fix the error below with least amount of modification +fn main() { + let x: i32 = 10; + { + let y: i32 = 5; + println!("The value of x is {} and value of y is {}", x, y); + } + println!("The value of x is {} and value of y is {}", x, y); +} +``` + +4. 🌟🌟 +```rust,editable + +// Fix the error with the use of define_x +fn main() { + println!("{}, world", x); +} + +fn define_x() { + let x = "hello"; +} +``` + +### Shadowing +You can declare a new variable with the same name as a previous variable, here we can say **the first one is shadowed by the second one.** + +5. 🌟🌟 +```rust,editable + +// Only modify `assert_eq!` to make the `println!` work(print `42` in terminal) +fn main() { + let x: i32 = 5; + { + let x = 12; + assert_eq!(x, 5); + } + + assert_eq!(x, 12); + + let x = 42; + println!("{}", x); // Prints "42". +} +``` + +6. 🌟🌟 +```rust,editable + +// Remove a line in the code to make it compile +fn main() { + let mut x: i32 = 1; + x = 7; + // Shadowing and re-binding + let x = x; + x += 3; + + + let y = 4; + // Shadowing + let y = "I can also be bound to text!"; + + println!("Success!"); +} +``` + +### Unused variables +7. Fix the warning below with : + +- 🌟 Only one solution +- 🌟🌟 Two distinct solutions + +> Note: none of the solutions is to remove the line `let x = 1` + +```rust,editable + +fn main() { + let x = 1; +} + +// Warning: unused variable: `x` +``` + +### Destructuring +8. 🌟🌟 We can use a pattern with `let` to destructure a tuple to separate variables. + +> Tips: you can use Shadowing or Mutability + +```rust,editable + +// Fix the error below with least amount of modification +fn main() { + let (x, y) = (1, 2); + x += 2; + + assert_eq!(x, 3); + assert_eq!(y, 2); + + println!("Success!"); +} +``` + +### Destructuring assignments +Introduced in Rust 1.59: You can now use tuple, slice, and struct patterns as the left-hand side of an assignment. + +9. 🌟🌟 + +> Note: the feature `Destructuring assignments` need 1.59 or higher Rust version + +```rust,editable + +fn main() { + let (x, y); + (x,..) = (3, 4); + [.., y] = [1, 2]; + // Fill the blank to make the code work + assert_eq!([x,y], __); + + println!("Success!"); +} +``` + + +> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it diff --git a/ro-RO/src/weak.md b/ro-RO/src/weak.md new file mode 100644 index 000000000..04b7a8f0c --- /dev/null +++ b/ro-RO/src/weak.md @@ -0,0 +1 @@ +# Weak and Circle reference diff --git a/ro-RO/src/why-exercise.md b/ro-RO/src/why-exercise.md new file mode 100644 index 000000000..33cb39370 --- /dev/null +++ b/ro-RO/src/why-exercise.md @@ -0,0 +1,47 @@ +
+ +
+ +

Practice Rust with challenging examples, exercises and projects

+ +
+ +[![Stars Count](https://img.shields.io/github/stars/sunface/rust-by-practice?style=flat)](https://github.com/sunface/rust-by-practice/stargazers) [![Forks Count](https://img.shields.io/github/forks/sunface/rust-by-practice.svg?style=flat)](https://github.com/naaive/orange/network/members) +[![LICENSE](https://img.shields.io/badge/license-mit-green?style=flat)](https://github.com/sunface/rust-by-practice/blob/master/LICENSE) +
+ +This book was designed for easily diving into and getting skilled with Rust, and it's very easy to use: All you need to do is to make each exercise compile without ERRORS and Panics ! + + +## Reading online + +- [English](https://practice.rs) +- [简体中文](https://zh.practice.rs) + + +## Running locally + +We use [mdbook](https://rust-lang.github.io/mdBook/) building our exercises. You can run locally with below steps: +```shell +$ git clone git@github.com:sunface/rust-by-practice.git +$ cargo install mdbook +$ cd rust-by-practice && mdbook serve en/ +``` + +## Features + +Part of our examples and exercises are borrowed from [Rust By Example](https://github.com/rust-lang/rust-by-example), thanks for your great works! + +Although they are so awesome, we have our own secret weapons :) + +- There are three parts in each chapter: examples, exercises and practices + +- Besides examples, we have `a lot of exercises`, you can Read, Edit and Run them ONLINE + +- Covering nearly all aspects of Rust, such as async/await, threads, sync primitives, optimizing, standard libraries, tool chain, data structures and algorithms etc. + +- Every exercise has its own solutions + +- The overall difficulties are a bit higher and from easy to super hard: easy 🌟 medium 🌟🌟 hard 🌟🌟🌟 super hard 🌟🌟🌟🌟 + +**What we want to do is fill in the gap between learning and getting started with real projects.** diff --git a/ro-RO/theme/index.hbs b/ro-RO/theme/index.hbs new file mode 100644 index 000000000..3fc804de4 --- /dev/null +++ b/ro-RO/theme/index.hbs @@ -0,0 +1,315 @@ + + + + + + {{ 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 livereload}} + + + {{/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}} + + + \ No newline at end of file diff --git a/ro-RO/theme/style1.css b/ro-RO/theme/style1.css new file mode 100644 index 000000000..4401632b9 --- /dev/null +++ b/ro-RO/theme/style1.css @@ -0,0 +1,81 @@ +@media only screen and (max-width:1080px) { + .sidetoc { + display: none !important; + } +} + +@media only screen and (min-width:1080px) { + main { + position: relative; + padding-right: 170px; + } + .sidetoc { + margin-left: auto; + margin-right: auto; + /*left: calc(100% + (var(--content-max-width))/4 - 180px);*/ + left: calc(100% - 200px); + position: absolute; + } + .pagetoc { + position: fixed; + width: 200px; + height: calc(100vh - var(--menu-bar-height) - 10rem); + overflow: auto; + z-index: 1000; + } + .pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--fg) !important; + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + font-size: 1.2rem; + } + .pagetoc a:hover, + .pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-fg) !important; + } + .pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-fg); + } +} + +.page-footer { + margin-top: 50px; + border-top: 1px solid #ccc; + overflow: hidden; + padding: 10px 0; + color: gray; +} + +/* 修改章节目录的间距 */ +.chapter li.chapter-item { + /* 没有文件时的文字颜色 */ + color: #939da3; + margin-top: 1rem; +} + +/* 修改滚动条宽度 */ +::-webkit-scrollbar { + width: 5px; +} + +/* 表格靠左对齐 */ +table { + margin-left: 0 !important; +} + +/* 只使用底部的页面跳转,因为左右两边的宽跳转会被 page-toc 遮盖 */ +@media only screen and (max-width: 2560px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} +@media only screen and (max-width: 2560px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +}