共计 4124 个字符,预计需要花费 11 分钟才能阅读完成。
流水不争先,争的是 滔滔不绝
, 积攒
比能力更重要; 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
Stack-Only Data: Copy
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.
&,&mut 地位不同区别
//eg:
let mut count:i32 = 0;
let count_borrowed:&mut i32 = &mut count; // 指向 i32 类型指针
*count_borrowed = 4;
//eg:
let mut number:i32 = 1;
let mut num_moved:i32 = number;
num_moved = 2;
闭包的类型
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();
}
&,&mut 与 ref, ref mut 区别?
Todo const-fn