let x = 3;
let y = 5_i32;
x = x + y;
println!("{}", x);
let x = 3;
let y = 5_i32;
let x = x + y;
println!("{}", x);
let x = 3.14_f32 as u32;
let y = 5_i32;
let z = x + y;
println!("{}", z);
let x = 3.14_f32 as u32;
let y = 5_i32;
let z = (x as u8) + (y as u8);
println!("{}", z);
let x = 13;
let y =
if (x > 42) {
println("Бабо, много ти е голям хикса!");
x
} elsif x == 42 {
println("Знам всичко!");
x
} else {
x
};
let x = loop { break { y } };
let x = 13;
let y = // Това е възможно
if x > 42 { // Няма кръгли скоби, 'къдравите' скоби са задължителни!
println!("Бабо, много ти е голям хикса!");
x
} else if x == 42 { // Няма elsif съкращения
println!("Знам всичко!"); // Macro!
x // Expression
} else {
x
};
let x = loop { break { 5 } }; // както и това
rustup
, cargo
, Rust Playground)
rustup doc
)
if
, while
, loop
)
fn
, връщане на стойности)
println!("x = {}", x)
)let x: (u32, bool) = (42, true);
println!("{}", x.0); // 42
println!("{}", x.1); // true
let (x, y) = (4, 5);
println!("{}", x); // 4
println!("{}", y); // 5
fn multi(x: i32, y: i32) -> (i32, i32, i32) {
(x * y, x + y, x - y)
}
let (a, b, c) = multi(4, 5);
let (d, e, _) = multi(4, 5); // Игнориране
let (_, f, _) = multi(4, 5); // Игнориране
let (a, b, c): (i32, i32, i32) = multi(4, 5);
// Пример за променливи върху стека
fn main() {
let a = 3;
let b = 42;
}
Примерни адреси:
0x7ffee0bb6c48 0x7ffee0bb6c4c
Правила
{
let a = 123;
// ...
}
a
е валидна от декларацията до края на scope-alet s = "hello";
let s = String::from("hello");
let mut second = String::from("Баба");
second.push_str(" и дядо"); // push_str() конкатенира литерал към String
println!("{}", second);
let mut first = "Баба";
// first.push_str(" и дядо"); // грешка при компилиране
let x = 5;
let y = x; // копие на стойността
println!("{}, {}", x, y);
let s1 = String::from("hello");
let s2 = s1; // ??
Побитово копиране на стека → двойна деалокация
Копие на стека и на динамичната памет, което може да доведе до сериозно забавяне
Вместо копиране, което е скъпо в някои случаи, Rust използва семантика на местене
let x = 5;
let y = x; // копие на стойността
let s1 = String::from("hello");
let s2 = s1; // s1 не може да се използва след този ред
println!("{}", s2);
// println!("{}", s1); // грешка при компилиране
Вместо копиране, което е скъпо в някои случаи, Rust използва семантика на местене
println!("{}", s2);
// println!("{}", s1); // грешка при компилиране
error[E0382]: use of moved value: `s1` --> src/main.rs:9:20 | 6 | let s2 = s1; | -- value moved here ... 9 | println!("{}", s1); | ^^ value used here after move | = note: move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
Ако все пак искаме да копираме String, може да го направим чрез метода clone()
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{}, {}!", s1, s2);
При подаването на аргументи към функция важат същите семантики
fn main() {
let s = String::from("hello"); // Дефинираме s
takes_ownership(s); // Стойността на s се мести във функцията и
// затова не е валидна след този ред.
} // Тук s излиза от scope, но s е преместен и не се случва нищо особено.
fn takes_ownership(some_string: String) {
println!("{}", some_string);
} // some_string излиза от scope и се извиква `drop`, което освобождава паметта.
При подаването на аргументи към функция важат същите семантики
fn main() {
let x = 5; // Дефинираме x
makes_copy(x); // Тук стойността на x би се преместила във функцията,
// но i32 е Copy, затова може да използваме x в последствие.
} // Тук x излиза от scope.
fn makes_copy(some_integer: i32) {
println!("{}", some_integer);
} // some_integer излиза от scope, но не се случва нищо особено.
Връщане на стойност от функция също може да прехвърля собственост
fn main() {
let s1 = gives_ownership();
let s2 = String::from("hello");
let s3 = takes_and_gives_back(s2);
}
fn gives_ownership() -> String {
let some_string = String::from("hello");
some_string // Тук местим стойността към функцията която е извикала gives_ownership
}
fn takes_and_gives_back(a_string: String) -> String {
a_string
}
fn main() {
let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}.", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len(); // len() връща дължината на String.
(s, length)
}
А какво ако искаме да използваме стойност във функция без да я местим всеки път?
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
error: cannot borrow immutable borrowed content `*some_string` as mutable --> error.rs:8:5 | 8 | some_string.push_str(", world"); | ^^^^^^^^^^^
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
1. По всяко време може да съществува само едно от следните:
2. Псевдонимите винаги са валидни
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
error[E0499]: cannot borrow `s` as mutable more than once at a time --> src/main.rs:5:19 | 4 | let r1 = &mut s; | - first mutable borrow occurs here 5 | let r2 = &mut s; | ^ second mutable borrow occurs here 6 | } | - first borrow ends here
let mut s = String::from("hello");
{
let r1 = &mut s;
}
let r2 = &mut s;
let s1 = String::from("hello");
let r = &s1;
let s2 = s1; // грешка
let r;
{
let s = String::from("hello");
r = &s;
}
println!("{}", r);
error[E0597]: `s` does not live long enough --> src/main.rs:6:5 | 5 | r = &s; | - borrow occurs here 6 | } | ^ `s` dropped here while still borrowed ... 9 | } | - borrowed value needs to live until here
let s = String::from("first");
let r = &s;
let s = String::from("second");
println!("{}", r);
println!("{}", s);
let s = String::from("hello");
let s = &s;
println!("{}", s);