Compiling rust_programming v0.1.0 (/home/zhaohang/repository/rust_programming) error[E0308]: mismatched types --> src/main.rs:4:29 | 4 | let n = example_closure(5); | --------------- ^ expected `String`, found integer | | | arguments to this function are incorrect | note: expected because the closure was earlier called with an argument of type `String` --> src/main.rs:3:29 | 3 | let s = example_closure(String::from("hello")); | --------------- ^^^^^^^^^^^^^^^^^^^^^ expected because this argument is of type `String` | | | in this closure call note: closure parameter defined here --> src/main.rs:2:28 | 2 | let example_closure = |x| x; | ^ help: try using a conversion method | 4 | let n = example_closure(5.to_string()); | ++++++++++++
For more information about this error, try `rustc --explain E0308`.
pubfnsearch<'a>(query: &str, contents: &'astr) ->Vec<&'astr> { // let mut result = Vec::new(); // for line in contents.lines() { // if line.contains(query) { // result.push(line); // } // }
// result
contents .lines() .filter(|line| line.contains(query)) .collect() } pubfnsearch_case_insensitive<'a>(query: &str, contents: &'astr) ->Vec<&'astr> { // let mut result = Vec::new(); // let query = query.to_lowercase(); // for line in contents.lines() { // if line.to_lowercase().contains(&query) { // result.push(line); // } // }
// result contents .lines() .filter(|line| line.to_lowercase().contains(query.to_lowercase().as_str())) .collect() }
In general, C++ implementations obey the zero-overhead principle: What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.
//! # My Crate //! //! `my_crate` is a collection of utilities to make performing certain //! calculations more convenient.
/// Adds one to the number given. // --snip--
使用 pub use 导出方便使用的公共 API
你开发时候使用的文件架构可能并不方便用户。你的结构可能是一个包含多个层级的分层结构,不过这对于用户来说并不方便。这是因为想要使用被定义在很深层级中的类型的人可能很难发现这些类型的存在。他们也可能会厌烦要使用 use my_crate::some_module::another_module::UsefulType; 而不是 use my_crate::UsefulType; 来使用类型。
有了唯一的名称、版本号、由 cargo new 新建项目时增加的作者信息、描述和所选择的 license,已经准备好发布的项目的 Cargo.toml 文件可能看起来像这样:
文件名: Cargo.toml
1 2 3 4 5 6 7 8 9
[package] name = "guessing_game" version = "0.1.0" edition = "2021" description = "A fun game where you guess what number the computer has chosen." license = "MIT OR Apache-2.0" author = "even629"
与此相对当 Rust 编译器检查像上例的 List 这样的递归类型时会发生什么呢。编译器尝试计算出储存一个 List 枚举需要多少内存,并开始检查 Cons 成员,那么 Cons 需要的空间等于 i32 的大小加上 List 的大小。为了计算 List 需要多少内存,它检查其成员,从 Cons 成员开始。Cons 成员储存了一个 i32 值和一个 List 值,这样的计算将无限进行下去
$ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) Finished dev [unoptimized + debuginfo] target(s) in0.60s Running `target/debug/drop-example` CustomSmartPointers created. Dropping CustomSmartPointer with data `other stuff`! Dropping CustomSmartPointer with data `my stuff`!
使用 std::mem::drop 来提前 drop 值
很难直接禁用自动的 drop 功能,也没必要
Drop trait 的目的就是进行自动的释放处理逻辑
Rust 不允许手动调用 Drop trait 的 drop 方法
但可以调用标准库的 std::mem::drop 函数(prelude),来提前 drop 值
文件名: src/main.rs
1 2 3 4 5 6 7 8
fnmain() { letc = CustomSmartPointer { data: String::from("some data"), }; println!("CustomSmartPointer created."); drop(c); println!("CustomSmartPointer dropped before the end of main."); }
运行这段代码会打印出如下:
1 2 3 4 5 6 7
$ cargo run Compiling drop-example v0.1.0 (file:///projects/drop-example) Finished dev [unoptimized + debuginfo] target(s) in0.73s Running `target/debug/drop-example` CustomSmartPointer created. Dropping CustomSmartPointer with data `some data`! CustomSmartPointer dropped before the end of main.
我们也无需担心意外的清理掉仍在使用的值,这会造成编译器错误:所有权系统确保引用总是有效的,也会确保 drop 只会在值不再被使用时被调用一次。
error[E0382]: use of moved value: `a` --> src/main.rs:11:30 | 9 | let a = Cons(5, Box::new(Cons(10, Box::new(Nil)))); | - move occurs because `a` has type `List`, which does not implement the `Copy` trait 10 | let b = Cons(3, Box::new(a)); | - value moved here 11 | let c = Cons(4, Box::new(a)); | ^ value used here after move
我们修改 List 的定义为使用 Rc 代替 Box,如列表 所示。现在每一个 Cons 变量都包含一个值和一个指向 List 的 Rc。当创建 b 时,不同于获取 a 的所有权,这里会克隆 a 所包含的 Rc,这会将引用计数从 1 增加到 2 并允许 a 和 b 共享 Rc 中数据的所有权。创建 c 时也会克隆 a,这会将引用计数从 2 增加为 3。每次调用 Rc::clone,Rc 中数据的引用计数都会增加,直到有零个引用之前其数据都不会被清理。
fnmain() { leta = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); println!("count after creating a = {}", Rc::strong_count(&a)); letb = Cons(3, Rc::clone(&a)); println!("count after creating b = {}", Rc::strong_count(&a)); { letc = Cons(4, Rc::clone(&a)); println!("count after creating c = {}", Rc::strong_count(&a)); } println!("count after c goes out of scope = {}", Rc::strong_count(&a)); }
这段代码会打印出:
1 2 3 4 5 6 7 8
$ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) Finished dev [unoptimized + debuginfo] target(s) in0.45s Running `target/debug/cons-list` count after creating a = 1 count after creating b = 2 count after creating c = 3 count after c goes out of scope = 2
我们能够看到 a 中 Rc 的初始引用计数为 1,接着每次调用 clone,计数会增加 1。当 c 离开作用域时,计数减 1。不必像调用 Rc::clone 增加引用计数那样调用一个函数来减少计数;Drop trait 的实现当 Rc 值离开作用域时自动减少引用计数。
从这个例子我们所不能看到的是,在 main 的结尾当 b 然后是 a 离开作用域时,此处计数会是 0,同时 Rc 被完全清理。使用 Rc 允许一个值有多个所有者,引用计数则确保只要任何所有者依然存在其值也保持有效。
$ cargo run Compiling borrowing v0.1.0 (file:///projects/borrowing) error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> src/main.rs:3:13
如下是一个我们想要测试的场景:
我们在编写一个记录某个值与最大值的差距的库,并根据当前值与最大值的差距来发送消息。例如,这个库可以用于记录用户所允许的 API 调用数量限额。
if percentage_of_max >= 1.0 { self.messenger.send("Error: You are over your quota!"); } elseif percentage_of_max >= 0.9 { self.messenger .send("Urgent warning: You've used up over 90% of your quota!"); } elseif percentage_of_max >= 0.75 { self.messenger .send("Warning: You've used up over 75% of your quota!"); } } } #[cfg(test)] mod tests { use super::*;
$ cargo test Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker) error[E0596]: cannot borrow `self.sent_messages` as mutable, as it is behind a `&` reference --> src/lib.rs:58:13 | 2 | fn send(&self, msg: &str); | ----- help: consider changing that to be a mutable reference: `&mut self` ... 58 | self.sent_messages.push(String::from(message)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
For more information about this error, try `rustc --explain E0596`. error: could not compile `limit-tracker` due to previous error warning: build failed, waiting for other jobs to finish... error: build failed
println!("b rc count after changing a = {}", Rc::strong_count(&b)); println!("a rc count after changing a = {}", Rc::strong_count(&a));
// Uncomment the next line to see that we have a cycle; // it will overflow the stack // println!("a next item = {:?}", a.tail()); }
如果保持最后的 println! 行注释并运行代码,会得到如下输出:
1 2 3 4 5 6 7 8 9 10 11
$ cargo run Compiling cons-list v0.1.0 (file:///projects/cons-list) Finished dev [unoptimized + debuginfo] target(s) in 0.53s Running `target/debug/cons-list` a initial rc count = 1 a next item = Some(RefCell { value: Nil }) a rc count after b creation = 2 b initial rc count = 1 b next item = Some(RefCell { value: Cons(5, RefCell { value: Nil }) }) b rc count after changing a = 2 a rc count after changing a = 2
如果取消最后 println! 的注释并运行程序,Rust 会尝试打印出 a 指向 b 指向 a 这样的循环直到栈溢出。这是因为:
很多操作系统提供了创建新线程的 API。这种由编程语言调用操作系统 API 创建线程的模型有时被称为 1:1,一个 OS 线程对应一个语言线程。Rust 标准库只提供了 1:1 线程实现;需要较小的运行时(即Rust 不需要额外的线程调度器或复杂机制,只需要跟踪线程句柄(handle),创建和销毁线程时调用 OS API,没有额外的用户态调度)。
$ cargo run Compiling threads v0.1.0 (file:///projects/threads) error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function --> src/main.rs:6:32 | 6 | let handle = thread::spawn(|| { | ^^ may outlive borrowed value `v` 7 | println!("Here's a vector: {:?}", v); | - `v` is borrowed here | note: function requires argument type to outlive `'static` --> src/main.rs:6:18 | 6 | let handle = thread::spawn(|| { | __________________^ 7 | | println!("Here's a vector: {:?}", v); 8 | | }); | |______^ help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword | 6 | let handle = thread::spawn(move || { | ++++ For more information about this error, try `rustc --explain E0373`. error: could not compile `threads` due to previous error
Rust 会 推断 如何捕获 v,因为 println! 只需要 v 的引用,闭包尝试借用 v。然而这有一个问题:Rust 不知道这个新建线程会执行多久,所以无法知晓 v 的引用是否一直有效。
示例 16-4 展示了一个 v 的引用很有可能不再有效的场景:
文件名: src/main.rs
1 2 3 4 5 6 7 8 9 10 11 12 13
use std::thread;
fnmain() { letv = vec![1, 2, 3];
lethandle = thread::spawn(|| { println!("Here's a vector: {:?}", v); });
一个日益流行的确保安全并发的方式是 消息传递(message passing),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档中]的口号:“不要通过共享内存来通讯;而是通过通讯来共享内存。”(“Do not communicate by sharing memory; instead, share memory by communicating.”)
$ cargo run Compiling message-passing v0.1.0 (file:///projects/message-passing) error[E0382]: borrow of moved value: `val` --> src/main.rs:10:31 | 8 | let val = String::from("hi"); | --- move occurs because `val` has type `String`, which does not implement the `Copy` trait 9 | tx.send(val).unwrap(); | --- value moved here 10 | println!("val is {}", val); | ^^^ value borrowed here after move
For more information about this error, try `rustc --explain E0382`. error: could not compile `message-passing` due to previous error
$ cargo run Compiling shared-state v0.1.0 (file:///projects/shared-state) error[E0382]: use of moved value: `counter` --> src/main.rs:9:36 | 5 | letcounter = Mutex::new(0); | ------- move occurs because `counter` has type `Mutex<i32>`, which does not implement the `Copy` trait ... 9 | lethandle = thread::spawn(move || { | ^^^^^^^ value moved into closure here, in previous iteration of loop 10 | letmut num = counter.lock().unwrap(); | ------- use occurs due to usein closure
For more information about this error, try `rustc --explain E0382`. error: could not compile `shared-state` due to previous error
$ cargo run Compiling shared-state v0.1.0 (file:///projects/shared-state) error[E0277]: `Rc<Mutex<i32>>` cannot be sent between threads safely --> src/main.rs:11:22 | 11 | let handle = thread::spawn(move || { | ______________________^^^^^^^^^^^^^_- | | | | | `Rc<Mutex<i32>>` cannot be sent between threads safely 12 | | let mut num = counter.lock().unwrap(); 13 | | 14 | | *num += 1; 15 | | }); | |_________- within this `[closure@src/main.rs:11:36: 15:10]` | = help: within `[closure@src/main.rs:11:36: 15:10]`, the trait `Send` is not implemented for `Rc<Mutex<i32>>` = note: required because it appears within the type `[closure@src/main.rs:11:36: 15:10]` note: required by a bound in `spawn`
For more information about this error, try `rustc --explain E0277`. error: could not compile `shared-state` due to previous error
第一行错误表明 Rc>cannot be sent between threads safely。编译器也告诉了我们原因 the traitSendis not implemented forRc>。下一部分会讲到 Send:这是确保所使用的类型可以用于并发环境的 trait 之一。
$ cargo run Compiling gui v0.1.0 (file:///projects/gui) error[E0277]: the traitbound `String: Draw` is not satisfied --> src/main.rs:5:26 | 5 | components: vec![Box::new(String::from("Hi"))], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Draw` is not implemented for `String` | = note: required forthe cast to the object type `dyn Draw`
For more information about this error, try `rustc --explain E0277`. error: could not compile `gui` due to previous error
$ cargo build Compiling gui v0.1.0 (file:///projects/gui) error[E0038]: the trait `Clone` cannot be made into an object --> src/lib.rs:2:29 | 2 | pub components: Vec<Box<dyn Clone>>, | ^^^^^^^^^ `Clone` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
For more information about this error, try `rustc --explain E0038`. error: could not compile `gui` due to previous error
ifletSome(color) = favorite_color{ print!("Using your favorite color,{},as the background",color); } elseif is_tuesday{ println!("Tuesday is green day!"); } elseifletOk(age) = age { if age > 30 { println!("Using purple as the background color"); } else { println!("Using orange as the background color"); } } else { println!("Using blue as the background color"); } }
对某些可能的值,无法进行匹配的模式:可辨驳的 例如:if let Some(x) = a_value
函数参数,let 语句,for 循环只接受无可辩驳的模式
if let 和 while let 接受可辨驳和无可辩驳的模式
1 2 3 4
fnmain() { leta: Option<i32> = Some(5); letSome(x) = a; }
输出
1 2 3 4 5 6 7 8
error[E0005]: refutable pattern inlocal binding: `None` not covered --> src\main.rs:3:9 | 3 | let Some(x) = a; | ^^^^^^^ pattern `None` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
无法匹配,因为模式没有覆盖 None 这种情况
修改
1 2 3 4 5 6
fnmain() { leta: Option<i32> = Some(5); ifletSome(x) = a{
}; }
match 除了最后一个分支,其它的分支都是可辨驳的,最后一个分支是不可辩驳的,因为它需要匹配所有剩余的情况
match p { Point {x,y:0}=> println!("On the x axis at {}",x),//要求y必须为0 Point {x:0,y} => println!("On the y axis at {}",y),//要求x必须为0 Point {x,y} => println!("On neither axis:({},{})",x,y), } }
enumMessage{ Quit, Move{x:i32,y:i32}, Write(String), ChangeColor(i32,i32,i32), } fnmain(){ letmsg = Message::ChangeColor(0, 160, 255); match msg { Message::Quit => { println!("The Quit variant has no data to destructure"); } Message::Move { x, y }=>{ println!("Move in the x direction {} and in the y direction {}",x,y); } Message::Write(text)=>{ println!("Text message:{}",text); } Message::ChangeColor(r, g, b)=>{ println!("rgb is ({},{},{})",r,g,b); } } }
#[derive(Debug)] enumMessage { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } fnmain() { letmsg = Message::Write(String::from("Hello World\n")); match msg { Message::Quit => { println!("The Quit variant has no data to destructure"); } Message::Move { x, y } => { println!("Move in the x direction {} and in the y direction {}", x, y); } Message::Write(text) => { println!("Text message:{}", text); } Message::ChangeColor(r, g, b) => { println!("rgb is ({},{},{})", r, g, b); } } println!("{:?}", msg); }
报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
error[E0382]: borrow of partially moved value: `msg` --> src/main.rs:24:22 | 17 | Message::Write(text) => { | ---- value partially moved here ... 24 | println!("{:?}", msg); | ^^^ value borrowed here after partial move | = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace formoreinfo) help: borrow this binding in the pattern to avoid moving the value | 17 | Message::Write(ref text) => { | +++
For more information about this error, try `rustc --explain E0382`. error: could not compile `rust_programming` (bin "rust_programming") due to 1 previous error
enumMessage { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } fnmain() { letmsg = Message::ChangeColor(0, 160, 255); match &msg { Message::Quit => { println!("The Quit variant has no data to destructure"); } Message::Move { x, y } => { println!("Move in the x direction {} and in the y direction {}", x, y); } Message::Write(text) => { println!("Text message:{}", text); } Message::ChangeColor(r, g, b) => { println!("rgb is ({},{},{})", r, g, b); } } }
enumColor{ Rgb(i32,i32,i32), Hsv(i32,i32,i32), } enumMessage{ Quit, Move{x:i32,y:i32}, Write(String), ChangeColor(Color), } fnmain(){ letmsg = Message::ChangeColor(Color::Hsv(0, 160, 255)); match msg { Message::ChangeColor(Color::Rgb(r, g, b))=>{ println!("Change the color to red {},green {},and blue {}",r,g,b); } Message::ChangeColor(Color::Hsv(h, s, v))=>{ println!("Change the color to hue {},saturation {},and value {}",h,s,v); } _ => (), } }
fnmain(){ lets = Some(String::from("Hello!")); ifletSome(_s) = s { println!("found a string"); } println!("{:?}",s); }
模式匹配中_s 是一个新的变量,模式匹配把 s 所有权移动到_s,后面再访问 s 就会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
error[E0382]: borrow of partially moved value: `s` --> src/main.rs:6:22 | 3 | iflet Some(_s) = s { | -- value partially moved here ... 6 | println!("{:?}", s); | ^ value borrowed here after partial move | = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: borrow this binding in the pattern to avoid moving the value | 3 | iflet Some(ref _s) = s { | +++
For more information about this error, try `rustc --explain E0382`. error: could not compile `rust_programming` (bin "rust_programming") due to 1 previous error
使用_
1 2 3 4 5 6 7
fnmain(){ lets = Some(String::from("Hello!")); ifletSome(_) = s { println!("found a string"); } println!("{:?}",s); }
_ ,不会发生绑定,不会移动所有权
..(忽略值的剩余部分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
structPoint{ x: i32, y: i32, z: i32, } fnmain(){ letorigin = Point{x:0,y:0,z:0}; match origin { Point {x,..} => println!("x is {}",x), }
fnmain(){ letnum = Some(4); match num { Some(x) if x < 5 => println!("less than five:{}",x), Some(x) => println!("{}",x), None => (), } } fnmain(){ letx = Some(5); lety = 10;
match x { Some(50) => println!("Got 50"), Some(n) if n==y => println!("Matched,n = {:?}",n),//这里if n==y不是一个模式,不会引用新的变量 _ =>println!("Default case,x ={:?}",x), } println!("at the end:x={:?},y={:?}",x,y); } fnmain(){ letx= 4; lety = false; match x { 4 | 5 | 6if y=> println!("yes"), _ => println!("no"), } }
@绑定
@ 符号可以让我们可以创建一个变量,该变量可以在测试某个值是否与模式匹配的同时保存该值
就相当于一个等号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
enumMessage{ Hello {id:i32}, } fnmain(){ letmsg = Message::Hello { id: 5 }; match msg { Message::Hello { id: id_variable @ 3..=7, }=>{ println!("Found an id in range:{}",id_variable); } Message::Hello { id: 10..=12 }=>{ println!("Found an id in another range"); } Message::Hello { id }=>{ println!("Found some other id:{}",id); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
structPoint { x: i32, y: i32, }
fnmain() { // fill in the blank to let p match the second arm letp = Point { x: 2, y: 20 }; // x can be [0, 5], y can be 10 20 or 30
match p { Point { x, y: 0 } => println!("On the x axis at {}", x), // second arm 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), } }
应用场景:
下面这段代码会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
enumMessage { Hello { id: i32 }, }
fnmain() { letmsg = Message::Hello { id: 5 };
match msg { Message::Hello { id: 3..=7, } => println!("id 值的范围在 [3, 7] 之间: {}", id),//Error cannot find value `id` in this scope Message::Hello { id: newid@10 | 11 | 12 } => {//Error variable `newid` is not bound in all patterns pattern doesn't bind `newid` println!("id 值的范围在 [10, 12] 之间: {}", newid) } Message::Hello { id } => println!("Found some other id: {}", id), } }
修复错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
enumMessage { Hello { id: i32 }, }
fnmain() { letmsg = Message::Hello { id: 5 };
match msg { Message::Hello { id: id @3..=7, } => println!("id 值的范围在 [3, 7] 之间: {}", id), Message::Hello { id: newid@(10 | 11 | 12) } => { println!("id 值的范围在 [10, 12] 之间: {}", newid) } Message::Hello { id } => println!("Found some other id: {}", id), } }
error[E0499]: cannot borrow `*slice` as mutable more than once at a time --> src\main.rs:6:29 | 3 | fn split_at_mut(slice:&mut[i32],mid:usize)->(&mut [i32],&mut[i32]){ | - let's call the lifetime of this reference `'1` ... 6 | (&mut slice[..mid],&mut slice[mid..]) | ------------------------^^^^^-------- | | | | | | | second mutable borrow occurs here | | first mutable borrow occurs here | returning this value requires that `*slice` is borrowed for `'1` For more information about this error, try `rustc --explain E0499`.
extern"C"{//"C"指明外部函数应用的二进制接口abi(application binary interface) fnabs(input: i32) ->i32;//想要调用的外部函数的签名 } fnmain(){ unsafe{ println!("Absolute value of -3 according to C:{}",abs(-3)); } }
// A trait which checks if 2 items are stored inside of container. // Also retrieves first or last value. traitContains { // Define generic types here which methods will be able to utilize. typeA; typeB;
implContainsforContainer { // Specify what types `A` and `B` are. If the `input` type // is `Container(i32, i32)`, the `output` types are determined // as `i32` and `i32`. typeA = i32; typeB = i32;
// `&Self::A` and `&Self::B` are also valid here. fncontains(&self, number_1: &i32, number_2: &i32) ->bool { (&self.0 == number_1) && (&self.1 == number_2) } // Grab the first number. fnfirst(&self) ->i32 { self.0 }
// Grab the last number. fnlast(&self) ->i32 { self.1 } }
fnmain() { 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), "21"); assert_eq!(format!("{1}{}{0}{}", 1, 2), "2112"); println!("Success!") }
assert_eq!(format!("{name}{}", 1, name = 2), "21"); assert_eq!(format!("{a} {c} {b}",a = "a", b = 'b', c = 3 ), "a 3 b");
// named argument must be placed after other arguments println!("{abc} {0}", 2, abc = "def");
println!("Success!") }
字符串对齐
默认情况下,通过空格来填充字符串
1 2 3 4 5 6 7 8 9 10
fnmain() { // the following two are padding with 5 spaces println!("Hello {:5}!", "x"); // => "Hello x !" println!("Hello {:1$}!", "x", 5); // => "Hello x !"
assert_eq!(format!("Hello {1:0$}!", 5, "x"), "Hello x !"); assert_eq!(format!("Hello {:width$}!", "x", width = 5), "Hello x !");
println!("Success!") }
左对齐, 右对齐, 使用指定的字符填充
1 2 3 4 5 6 7 8 9 10 11 12 13
fnmain() { // left align println!("Hello {:<5}!", "x"); // => Hello x ! // right align assert_eq!(format!("Hello {:>5}!", "x"), "Hello x!"); // center align assert_eq!(format!("Hello {:^5}!", "x"), "Hello x !");
// left align, pad with '&' assert_eq!(format!("Hello {:&<5}!", "x"), "Hello x&&&&!");
They get told that "str literal" is hardcoded into the compiled binary and is loaded into read-only memory at run-time so it’s immutable and valid for the entire program and that’s what makes it 'static. These concepts are further reinforced by the rules surrounding defining static variables using the static keyword.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Note: This example is purely for illustrative purposes. // Never use `static mut`. It's a footgun. There are // safe patterns for global mutable singletons in Rust but // those are outside the scope of this article.
The 'static lifetime was probably named after the default lifetime of static variables, right? So it makes sense that the 'static lifetime has to follow all the same rules, right?
Well yes, but a type with a 'static lifetime is different from a type bounded by a 'static lifetime. The latter can be dynamically allocated at run-time, can be safely and freely mutated, can be dropped, and can live for arbitrary durations.
It’s important at this point to distinguish &'static T from T: 'static.
&'static T is an immutable reference to some T that can be safely held indefinitely long, including up until the end of the program. This is only possible if T itself is immutable and does not move after the reference was created. T does not need to be created at compile-time. It’s possible to generate random dynamically allocated data at run-time and return 'static references to it at the cost of leaking memory, e.g.
1 2 3 4 5 6 7
use rand;
// generate random 'static str refs at run-time fnrand_str_generator() -> &'staticstr { letrand_string = rand::random::<u64>().to_string(); Box::leak(rand_string.into_boxed_str()) }
T: 'static is some T that can be safely held indefinitely long, including up until the end of the program. T: 'static includes all &'static T however it also includes all owned types, like String, Vec, etc. The owner of some data is guaranteed that data will never get invalidated as long as the owner holds onto it, therefore the owner can safely hold onto the data indefinitely long, including up until the end of the program. T: 'static should be read as “T is bounded by a 'static lifetime” not “T has a 'static lifetime”. A program to help illustrate these concepts:
fnmain() { letmut strings: Vec<String> = Vec::new(); for_in0..10 { if rand::random() { // all the strings are randomly generated // and dynamically allocated at run-time letstring = rand::random::<u64>().to_string(); strings.push(string); } }
// strings are owned types so they're bounded by 'static formut string in strings { // all the strings are mutable string.push_str("a mutation"); // all the strings are droppable drop_static(string); // ✅ }
// all the strings have been invalidated before the end of the program println!("I am the end of the program"); }
Key Takeaways
T: 'static should be read as “T is bounded by a 'static lifetime”
if T: 'static then T can be a borrowed type with a 'static lifetime or an owned type