Rust2 Common Programming Concepts Understanding Ownership

编程入门 行业动态 更新时间:2024-10-28 19:30:06

Rust2 Common <a href=https://www.elefans.com/category/jswz/34/1751576.html style=Programming Concepts Understanding Ownership"/>

Rust2 Common Programming Concepts Understanding Ownership

Rust学习笔记

Rust编程语言入门教程课程笔记

参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community)

Lecture 3 Common Programming Concepts

fn main() {// Variables and Mutabilitylet mut x = 5; // mut means mutableprintln!("The value of x is: {x}");x = 6;println!("The value of x is: {x}");// Constantsconst THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3; // all caps with underscoresprintln!("The value of THREE_HOURS_IN_SECONDS is: {THREE_HOURS_IN_SECONDS}");// Shadowinglet y = 5;println!("The value of y is: {y}");let y = y + 1; //shadowing// this is allowed because we are creating a new variableprintln!("The value of y is: {y}");// Shadowing vs Mutabilitylet spaces = "   ";let spaces = spaces.len(); // this is allowed because we are creating a new variableprintln!("The value of spaces is: {spaces}");// Data Typeslet guess: u32 = "42".parse().expect("Not a number!"); // type annotationprintln!("The value of guess is: {guess}");let m = 57u8; // u8println!("The value of m is: {m}");let n = 1_000_000; // i32println!("The value of n is: {n}");let x = 2.0; // f64let y: f32 = 3.0; // f32println!("The value of x is: {x}");println!("The value of y is: {y}");// additionlet sum = 5 + 10;println!("The value of sum is: {sum}");// subtractionlet difference = 95.5 - 4.3;println!("The value of difference is: {difference}");// multiplicationlet product = 4 * 30;println!("The value of product is: {product}");// divisionlet quotient = 56.7 / 32.2;let truncated = -5 / 3; // Results in -1println!("The value of quotient is: {quotient}");println!("The value of truncated is: {truncated}");// remainderlet remainder = 43 % 5;println!("The value of remainder is: {remainder}");// booleanlet t = true;let f: bool = false; // with explicit type annotationprintln!("The value of t is: {t}");println!("The value of f is: {f}");// characterlet c = 'z';let z: char = 'ℤ'; // with explicit type annotationlet heart_eyed_cat = '😻';println!("The value of c is: {c}");println!("The value of z is: {z}");println!("The value of heart_eyed_cat is: {heart_eyed_cat}");// Compound Types// Tuplelet tup: (i32, f64, u8) = (500, 6.4, 1); // type annotationprintln!("The value of tup is: {:?}", tup);let (x, y, z) = tup; // destructuringprintln!("The value of x is: {x}");println!("The value of y is: {y}");println!("The value of z is: {z}");let five_hundred = tup.0; // accessing tuple elementsprintln!("The value of five_hundred is: {five_hundred}");let six_point_four = tup.1;println!("The value of six_point_four is: {six_point_four}");let one = tup.2;println!("The value of one is: {one}");//Array //saved on stack// fixed length and same typelet a = [1, 2, 3, 4, 5]; // arrayprintln!("The value of a is: {:?}", a);let a = [3; 5]; // [3, 3, 3, 3, 3] // [element; size]let first = a[0];let second = a[1];println!("The value of first is: {first}");println!("The value of second is: {second}");// Functionsanother_function(5);println!("The value of add_five(10) is: {}", add_five(10));// Control Flow// if-else flowlet number = 6;if number % 4 == 0 {println!("number is divisible by 4");} else if number % 3 == 0 {println!("number is divisible by 3");} else if number % 2 == 0 {println!("number is divisible by 2");} else {println!("number is not divisible by 4, 3, or 2");}let condition = true;let number = if condition { 5 } else { 6 };println!("The value of number is: {number}");// loop flowlet mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2; // break with value}// no semicolon here};// semicolon hereprintln!("The value of result is: {result}");// while flowlet mut number = 3;while number != 0 {println!("{}!", number);number -= 1;}// no semicolon hereprintln!("LIFTOFF!!!");// for flowlet a = [10, 20, 30, 40, 50];   for element in a.iter() {// iter() returns each element in a collectionprintln!("the value is: {element}");}// no semicolon herefor number in 1..4 {// range [1, 4) = [1, 2, 3]println!("{}!", number);}for number in (1..4).rev() {// reverse println!("{}!", number);}}fn another_function(x: i32) {// type annotationprintln!("Another function.");println!("The value of x is: {x}");
}fn add_five(x: i32) -> i32 {5 + x // no semicolon means return
}

Lecture 4 Understanding Ownership

fn main() {//Ownership is a set of rules that govern how a Rust program manages memory.//These rules are checked at compile time.//Ownership is Rust's most unique feature, and it enables Rust to make memory safety guarantees without needing a garbage collector.//All programs have to manage the way they use a computer's memory while running.//Stack and Heap//All data stored on the stack must have a known, fixed size. //Data with an unknown size at compile time or a size that might change must be stored on the heap instead.//The main purpose of ownership is to manage heap data.//Ownership Rules//1. Each value in Rust has a variable that’s called its owner.//2. There can only be one owner at a time.//3. When the owner goes out of scope, the value will be dropped.//Variable Scopelet mut s = String::from("hello");//The String type is allocated on the heap.s.push_str(", world!"); // push_str() appends a literal to a Stringprintln!("{}", s); // This will print `hello, world!`//Memory and Allocation//With the String type, in order to support a mutable, growable piece of text, we need to allocate an amount of memory on the heap, unknown at compile time, to hold the contents. This means://1. The memory must be requested from the memory allocator at runtime.//2. We need a way of returning this memory to the allocator when we’re done with our String.//Rust takes a different path: //the memory is automatically returned once the variable that owns it goes out of scope.//Movelet x = 5;let y = x; //Stack-Only Data: Copyprintln!("x = {}, y = {}", x, y);//This works because integers are simple values with a known, fixed size, and these two 5 values are pushed onto the stack.let s1 = String::from("hello");let s2 = s1;//println!("{}, world!", s1);//This will throw an error because Rust considers s1 to no longer be valid and, therefore, Rust doesn’t need to free anything when s1 goes out of scope.println!("{}, world!", s2);//This will work because s2 is the new owner of the String data.//Clonelet s1 = String::from("hello");let s2 = s1.clone();println!("s1 = {}, s2 = {}", s1, s2);//This will work because s1.clone() creates a deep copy of the String data, not just a copy of the stack pointer.//Ownership and Functionslet s = String::from("hello");  // s comes into scope.takes_ownership(s);             // s's value moves into the function...// ... and so is no longer valid here.let x = 5;                      // x comes into scope.makes_copy(x);                  // x would move into the function,// but i32 is Copy, so it’s okay to still// use x afterward.//println!("{}", s);//This will throw an error because s is no longer valid.println!("{}", x);//This will work because x is still valid.//Return Values and Scopelet s1 = gives_ownership();         // gives_ownership moves its return// value into s1.let s2 = String::from("hello");     // s2 comes into scope.let s3 = takes_and_gives_back(s2);  // s2 is moved into// takes_and_gives_back, which also// moves its return value into s3.println!("s1 = {}, s3 = {}", s1, s3);//Here, s3 goes out of scope and is dropped. s2 goes out of scope but was moved, so nothing happens. s1 goes out of scope and is dropped.//println!("{}", s2);//This will throw an error because s2 is no longer valid.//References and Borrowinglet s1 = String::from("hello");let len = calculate_length(&s1);//The &s1 syntax lets us create a reference that refers to the value of s1 but does not own it.println!("The length of '{}' is {}.", s1, len);//This will work because s1 is still valid.//Mutable Referenceslet mut s = String::from("hello");change(&mut s);//We can have only one mutable reference to a particular piece of data in a particular scope.println!("{}", s);//This will work because s is still valid.let mut s = String::from("hello");let r1 = &mut s;//let r2 = &mut s;//This will throw an error because we can have only one mutable reference to a particular piece of data in a particular scope.//println!("{}, {}", r1, r2);println!("{}", r1);let mut s = String::from("hello");{let r1 = &mut s;println!("{}", r1);} // r1 goes out of scope here, so we can make a new reference with no problems.let r2 = &mut s;println!("{}", r2);let s = String::from("hello");let r1 = &s; // no problemlet r2 = &s; // no problem//let r3 = &mut s; // BIG PROBLEM //This will throw an error because we can have either one mutable reference or any number of immutable references.println!("{}, {}", r1, r2);//Note that a reference’s scope starts from where it is introduced and continues through the last time that reference is used.let mut s = String::from("hello");let r1 = &s; // no problemlet r2 = &s; // no problemprintln!("{} and {}", r1, r2);// variables r1 and r2 will not be used after this pointlet r3 = &mut s; // no problemprintln!("{}", r3);//Dangling Referenceslet reference_to_nothing = dangle();println!("{}", reference_to_nothing);//The Rules of References//1. At any given time, you can have either one mutable reference or any number of immutable references.//2. References must always be valid.//The Slice Type//Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection. A slice is a kind of reference, so it does not have ownership.//Find the first word in a stringlet s = String::from("hello world");//let wordIndex = first_word(&s);let first = first_word(&s);//s.clear();//This will throw an error because we have an immutable reference to s.println!("the first word is: {}", first);let hello = &s[..5]; //[starting_index..ending_index) = [0..5) = [0, 1, 2, 3, 4]let world = &s[6..]; //[starting_index..ending_index) = [6..11) = [6, 7, 8, 9, 10]println!("{} {}", hello, world);//Other Sliceslet a = [1, 2, 3, 4, 5];let slice = &a[1..3];//[starting_index..ending_index) = [1..3) = [1, 2]assert_eq!(slice, &[2, 3]);//The assert_eq! macro tests whether two expressions are equal to each other; if they are, nothing happens, and if they aren’t, the macro prints the two expressions and panics.}   fn takes_ownership(some_string: String) { // some_string comes into scope.println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing memory is freed.fn makes_copy(some_integer: i32) { // some_integer comes into scope.println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.fn gives_ownership() -> String {             // gives_ownership will move its// return value into the function// that calls it.let some_string = String::from("hello"); // some_string comes into scope.some_string                             // some_string is returned and// moves out to the calling// function.
}fn takes_and_gives_back(a_string: String) -> String { // a_string comes into// scope.a_string  // a_string is returned and moves out to the calling function.
}fn calculate_length(s: &String) -> usize {//We call having references as function parameters borrowing.s.len()
}//Here, s goes out of scope. But because it does not have ownership of what it refers to, nothing happens.fn change(some_string: &mut String) {some_string.push_str(", world");
}// fn dangle() -> &String { //This will throw an error because we are trying to return a reference to a String that is created inside the function.
//     let s = String::from("hello");
//     &s
// }//Here, s goes out of scope, and is dropped. Its memory goes away. Danger!fn dangle() -> String {let s = String::from("hello");s
}// fn first_word(s: &String) -> usize {
//     let bytes = s.as_bytes();//     for (i, &item) in bytes.iter().enumerate() {
//         if item == b' ' {
//             return i;
//         }
//     }//     s.len()
// }fn first_word(s: &String) -> &str {//We can use &str as the type of the slice parameter to make it clear that the keys function will return slices of String values rather than whole String values.let bytes = s.as_bytes();for (i, &item) in bytes.iter().enumerate() {//The enumerate method returns a tuple consisting of the index and the reference to the element.if item == b' ' {return &s[0..i];}}&s[..]
}//1. fn first_word(s: &String) -> &str
//2. fn first_word(s: &str) -> &str
//A more experienced Rustacean would write the signature shown in type 2 instead because it allows us to use the same function on both &String values and &str values.

更多推荐

Rust2 Common Programming Concepts Understanding Ownership

本文发布于:2023-11-16 11:51:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1620022.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Programming   Common   Ownership   Understanding   Concepts

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!