流水不争先,争的是滔滔不绝
,积累
比能力更重要; rust语法能看懂,尝试写一些东西却写不出来或不够简练,眼高手低
.
Copy & Clone
Stack-Only Data:Copy
The Copy trait allows you to duplicate(复制?) a value by only copying bits stored on the stack;
A type that implements Copy must also implement Clone, because a type that implements Copy has a trivial(无关紧要?) implementation of Clone that performs the same task as Copy;
Everything possible with Copy you can also accomplish with Clone, but the code might be slower or have to use clone in places(在某些地方).
If a type implements the Copy trait, a variable is still valid after assignment to another variable
let num_a = 3;
let num_b = num_a.clone(); // let num_b = num_a; 等价写法,省略clone()
println!("{}",num_a); //测试num_a 是否 move
Here are some of the types that implement Copy:
- All the integer types, such as u32.
- The Boolean type, bool, with values true and false.
- All the floating point types, such as f64.
- The character type, char.
- Tuples, if they only contain types that also implement Copy. For example, (i32, i32) implements Copy, but (i32, String) does not.
enum,struct 默认没有实现Copy trait
Clone-and-copy-for-duplicating-values
Slice
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.
Slices are similar to arrays, but their length is not known at compile time.
Instead, a slice is a two-word object, the first word is a pointer to the data, and the second word is the length of the slice. The word size is the same as usize, determined by the processor architecture eg 64 bits on an x86-64.
let array = [3,4,5,6,7];
let subArr = array[0..2]; //error: the size for values of type `[{integer}]` can not be known at compilation time
//array是一个slice,尽管这里我们可以计算出来这里有两个元素;
//但是编译器无法得知(试想一种情况如果我们 subArr 传给 fn t1(swap:[u8]){
//在这个函数中无法获取swap的大小})
注意这里的array[0..2] 才是slice 类型为[u8], 它的数据结构不是 pointer + length,个人感觉只是一个指向 array 的指针; 而 &array[0..2] 的数据结构才是 pointer + length; 所以这里要写成 let subArr = &array[0..2]; 才可以通过编译;
Slices can be created from both arrays and vectors.
String Literals Are Slices
let s = "Hello, world!"; //s here is &str
&str accept both &String values and &str values
mut,&mut 不同位置时的作用
//eg: &mut
let mut count:i32 = 0;
let count_borrowed:&mut i32 = &mut count; //指向i32类型指针
*count_borrowed = 4;
//eg: mut
let mut number:i32 = 1;
let mut num:i32 = number;
num = 2;
//eg: mut
let y = 3;
let mut count = 0;
let x = & mut count; // 等价写法 let x:& mut i32 = & mut count;
*x = 8;
let mut z = &count;
z = &y;
闭包的类型
Storing-closures-using-generic-parameters-and-the-fn-traits
Each closure instance has its own unique anonymous type: that is, even if two closures have the same signature, their types are still considered different. To define structs, enums, or function parameters that use closures, we use generics and trait bounds;The Fn traits are provided by the standard library. All closures implement at least one of the traits: Fn, FnMut, or FnOnce;
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
Capturing-the-environment-with-closures
闭包变量捕获
When a closure captures a value from its environment, it uses memory to store the values for use in the closure body. This use of memory is overhead that we don’t want to pay in more common cases where we want to execute code that doesn’t capture its environment. Because functions are never allowed to capture their environment, defining and using functions will never incur this overhead.
Closures can capture values from their environment in three ways, which directly map to the three ways a function can take a parameter: taking ownership, borrowing mutably, and borrowing immutably. These are encoded in the three Fn traits as follows:
- FnOnce consumes the variables it captures from its enclosing scope, known as the closure’s environment. To consume the captured variables, the closure must take ownership of these variables and move them into the closure when it is defined. The Once part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can be called only once.
- FnMut can change the environment because it mutably borrows values.
- Fn borrows values from the environment immutably.
When you create a closure, Rust infers which trait to use based on how the closure uses the values from the environment. All closures implement FnOnce because they can all be called at least once. Closures that don’t move the captured variables also implement FnMut, and closures that don’t need mutable access to the captured variables also implement Fn.
If you want to force the closure to take ownership of the values it uses in the environment, you can use the move keyword before the parameter list. This technique is mostly useful when passing a closure to a new thread to move the data so it’s owned by the new thread.
Functions can implement all three of the Fn traits too. If what we want to do doesn’t require capturing a value from the environment, we can use a function rather than a closure where we need something that implements an Fn trait(函数不能捕获变量);
Closures can capture variables:
- by reference: &T
- by mutable reference: &mut T
- by value: T
use std::mem;
fn main() {
let t1 = "XXX";
let mut s1 = "YYY".to_string();
//move
let cc = move ||{
println!("Result:{}",t1); // Fn() &T 引用
s1.push_str("ff"); //FnMut() &mut T 可变引用
//mem::drop(s1); //FnOnce()
//move //FnOnce() T
};
apply_f(cc);
println!("After t1:{} ",t1);
//println!("After s1:{} ",s1); //使用move之后 s1无法访问
}
fn apply_f<F>(f:F)
where F:FnOnce()
{
f();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。