first commit

pull/89/head
sunface 3 years ago
commit beaa7bebc1

@ -0,0 +1,23 @@
# The Way To Rust(Rust编程指南)
## Rust学习路线
0. 入一个社区: [Rust CN Members](https://rust.cm)
1. 读一本好书: [<<Rust编程指南>>](https://mastery.rs)
2. 做一些习题: [Rust Excersise](https://github.com/rustcm/rustex)
3. 看一个项目: [Simple Redis](https://github.com/rustcm/simple-redis)
4. 学常用算法: [Algorithms](https://github.com/rustcm/algorithms)
5. 找优秀开源: [Awesome Rust](https://github.com/rustcm/awesome-rust)
## 我们的愿景
愿景不是少数人的Rust而是大家的Rust。
Rust语言目前在世界范围已经发展的如火如荼但是在国内还是非常小众终其原因是因为我们缺少一整套学习生态现有的Rust资料几乎没有用中文书写的就算有也往往不成体系。
我们想做的就是跟大家一起打造一个真正的中国Rust社区同时辅以完整的Rust进阶体系帮助中国的程序员快速上手Rust并能在实际项目中进行应用只有降低了这个门槛才能真正迎来Rust未来在中国的大爆发。
这个目标任重而道远欢迎有志之士的加入QQ群933696593
## 版本修订
本书每半年会修订一次保证书籍的内容会跟上最新的Rust内容

@ -0,0 +1,3 @@
整理几个可以作为学习demo的项目需要将注释和相关文档翻译成中文
1. [mini-redis](https://github.com/tokio-rs/mini-redis)

@ -0,0 +1,11 @@
Rust相关英文书籍
1. [Rust语言基础教学](https://doc.rust-lang.org/book/)
2. [Rust语言示例](https://doc.rust-lang.org/stable/rust-by-example/index.html)
3. [Cargo教学](https://doc.rust-lang.org/cargo/index.html)
4. [Rust性能之书](https://nnethercote.github.io/perf-book/title-page.html)
5. [Rust异步编程](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html)

@ -0,0 +1,230 @@
# 命名规范
基本的Rust命名规范在[RFC 430]中有描述.
通常,对于"type-level"的构造Rust倾向于使用驼峰命名,而对于'value-level'的构造使用蛇形命名。详情如下:
| 条目 | 惯例 |
| ---- | ---------- |
| 包Crates | [unclear](https://github.com/rust-lang/api-guidelines/issues/29) |
| 模块Modules | `snake_case` |
| 类型Types | `UpperCamelCase` |
| 特征Traits | `UpperCamelCase` |
| 枚举变量Enum variants | `UpperCamelCase` |
| 函数Functions | `snake_case` |
| 方法Methods | `snake_case` |
| 通用构造器General constructors | `new` or `with_more_details` |
| 转换构造器Conversion constructors | `from_some_other_type` |
| 宏Macros | `snake_case!` |
| 局部变量Local variables | `snake_case` |
| 静态类型Statics | `SCREAMING_SNAKE_CASE` |
| 常量Constants | `SCREAMING_SNAKE_CASE` |
| 类型参数Type parameters | `UpperCamelCase`, 通常使用一个大写字母: `T` |
| 生命周期Lifetimes | 通常使用小写字母: `'a`, `'de`, `'src` |
| Features | [unclear](https://github.com/rust-lang/api-guidelines/issues/101) but see [C-FEATURE] |
对于驼峰命名法, 复合词的缩略形式我们认为是一个单独的词语,所以只对首字母进行大写: 使用`Uuid`而不是`UUID`, `Usize`而不是`USize`, `Stdin`而不是`StdIn`.对于蛇形命名法,缩略词用全小写: `is_xid_start`.
对于蛇形命名(包括全大写的`SCREAMING_SNAKE_CASE`), 除了最后一部分,其它部分的词语都不能由单个字母组成:
`btree_map`而不是`b_tree_map`, `PI_2`而不是`PI2`.
包名不应该使用`-rs`或者`-rust`作为后缀因为每一个包都是Rust写的因此这种多余的注释其实没有任何意义。
[RFC 430]: https://github.com/rust-lang/rfcs/blob/master/text/0430-finalizing-naming-conventions.md
[C-FEATURE]: #c-feature
## 类型转换要遵守`as_`, `to_`, `into_`命名惯例(C-CONV)
类型转换应该通过方法调用的方式实现,其中的前缀规则如下:
| 方法前缀 | 性能开销 | 所有权改变 |
| ------ | ---- | --------- |
| `as_` | Free | borrowed -\> borrowed |
| `to_` | Expensive | borrowed -\> borrowed<br>borrowed -\> owned (non-Copy types)<br>owned -\> owned (Copy types) |
| `into_` | Variable | owned -\> owned (non-Copy types) |
For example:
- [`str::as_bytes()`] 把`str`变成UTF-8字节数组, 性能开销是0. 其中输入是一个借用的`&str`,输出也是一个借用的`&str`.
- [`Path::to_str`] 会执行一次昂贵的UTF-8字节数组检查输入和输出都是借用的。对于这种情况如果把方法命名为`as_str`是不正确的,因为这个方法的开销还挺大.
- [`str::to_lowercase()`]在调用过程中会遍历字符串的字符,且可能会分配新的内存对象.输入是一个借用的`str`,输出是一个有独立所有权的`String`
- [`String::into_bytes()`]返回`String`底层的`Vec<u8>`数组,转换本身是零消耗的。该方法获取`String`的所有权,然后返回一个新的有独立所有权的`Vec<u8>`
[`str::as_bytes()`]: https://doc.rust-lang.org/std/primitive.str.html#method.as_bytes
[`Path::to_str`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.to_str
[`str::to_lowercase()`]: https://doc.rust-lang.org/std/primitive.str.html#method.to_lowercase
[`f64::to_radians()`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians
[`String::into_bytes()`]: https://doc.rust-lang.org/std/string/struct.String.html#method.into_bytes
[`BufReader::into_inner()`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.into_inner
[`BufWriter::into_inner()`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html#method.into_inner
当一个单独的值被某个类型所包装时,访问该类型的内部值应通过`into_inner()`方法来访问。例如将一个缓冲区值包装为[`BufReader`]类型,还有[`GzDecoder`]、[`AtomicBool`]等,都是这种类型。
[`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.into_inner
[`GzDecoder`]: https://docs.rs/flate2/0.2.19/flate2/read/struct.GzDecoder.html#method.into_inner
[`AtomicBool`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.into_inner
如果`mut`限定符在返回类型中出现,那么在命名上也应该体现出来。例如,[`Vec::as_mut_slice`] 就说明它返回了一个mut切片在这种情况下`as_mut_slice`比`as_slice_mut`更适合。
[`Vec::as_mut_slice`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.as_mut_slice
```rust
// 返回类型是一个mut切片.
fn as_mut_slice(&mut self) -> &mut [T];
```
##### 标准库中的一些例子
- [`Result::as_ref`](https://doc.rust-lang.org/std/result/enum.Result.html#method.as_ref)
- [`RefCell::as_ptr`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.as_ptr)
- [`slice::to_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.to_vec)
- [`Option::into_iter`](https://doc.rust-lang.org/std/option/enum.Option.html#method.into_iter)
## 读访问器(Getter)的名称遵循Rust的命名规范(C-GETTER)
除了少数例外在Rust代码中`get`前缀不用于getter。
```rust
pub struct S {
first: First,
second: Second,
}
impl S {
// 而不是get_first
pub fn first(&self) -> &First {
&self.first
}
// 而不是get_first_mut, get_mut_first, or mut_first.
pub fn first_mut(&mut self) -> &mut First {
&mut self.first
}
}
```
至于上文提到的少数例外如下当有且仅有一个值能被getter所获取时才使用`get`前缀。例如,
[`Cell::get`]能直接访问到`Cell`中的内容。
[`Cell::get`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get
有些getter会在过程中执行运行时检查那么我们就可以考虑添加`_unchecked`getter函数这个函数虽然不安全但是往往具有更高的性能
典型的例子如下:
```rust
fn get(&self, index: K) -> Option<&V>;
fn get_mut(&mut self, index: K) -> Option<&mut V>;
unsafe fn get_unchecked(&self, index: K) -> &V;
unsafe fn get_unchecked_mut(&mut self, index: K) -> &mut V;
```
[`TempDir::path`]: https://docs.rs/tempdir/0.3.5/tempdir/struct.TempDir.html#method.path
[`TempDir::into_path`]: https://docs.rs/tempdir/0.3.5/tempdir/struct.TempDir.html#method.into_path
### 标准库示例
- [`std::io::Cursor::get_mut`](https://doc.rust-lang.org/std/io/struct.Cursor.html#method.get_mut)
- [`std::ptr::Unique::get_mut`](https://doc.rust-lang.org/std/ptr/struct.Unique.html#method.get_mut)
- [`std::sync::PoisonError::get_mut`](https://doc.rust-lang.org/std/sync/struct.PoisonError.html#method.get_mut)
- [`std::sync::atomic::AtomicBool::get_mut`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.get_mut)
- [`std::collections::hash_map::OccupiedEntry::get_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.OccupiedEntry.html#method.get_mut)
- [`<[T]>::get_unchecked`](https://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked)
## 一个集合上的方法,如果返回迭代器,需遵循命名规则:`iter`, `iter_mut`, `into_iter` (C-ITER)
```rust
fn iter(&self) -> Iter // Iter implements Iterator<Item = &U>
fn iter_mut(&mut self) -> IterMut // IterMut implements Iterator<Item = &mut U>
fn into_iter(self) -> IntoIter // IntoIter implements Iterator<Item = U>
```
上面的规则适用于同构性的数据集合。与之相反,`str`类型是一个utf8字节数组切片与同构性集合有一点微妙的差别它可以认为是字节集合也可以认为是字符集合因此它提供了[`str::bytes`]去遍历字节,还有[`str::chars`]去遍历字符,而并没有直接定义`iter`等方法。
[`str::bytes`]: https://doc.rust-lang.org/std/primitive.str.html#method.bytes
[`str::chars`]: https://doc.rust-lang.org/std/primitive.str.html#method.chars
上述规则只适用于方法,并不适用于函数。例如`url`包的[`percent_encode`]函数返回一个迭代器用于遍历百分比编码([Percent encoding](https://en.wikipedia.org/wiki/Percent-encoding))的字符串片段. 在这种情况下,使用`iter`/`iter_mut`/`into_iter`诸如此类的函数命名无法表达任何具体的含义。
[`percent_encode`]: https://docs.rs/url/1.4.0/url/percent_encoding/fn.percent_encode.html
[RFC 199]: https://github.com/rust-lang/rfcs/blob/master/text/0199-ownership-variants.md
### 标准库示例
- [`Vec::iter`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter)
- [`Vec::iter_mut`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter_mut)
- [`Vec::into_iter`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_iter)
- [`BTreeMap::iter`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.iter)
- [`BTreeMap::iter_mut`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.iter_mut)
## 迭代器的类型应该与产生它的方法名相匹配(C-ITER-TY)
例如形如`into_iter()`的方法应该返回一个`IntoIter`类型,与之相似,其它任何返回迭代器的方法也应该遵循这种命名惯例。
上述规则主要应用于方法但是经常对于函数也适用。例如上文提到的url包中的[`percent_encode`]函数,返回了一个[`PercentEncode`]类型.
[PercentEncode-type]: https://docs.rs/url/1.4.0/url/percent_encoding/struct.PercentEncode.html
特别是,当这些类型跟包名前缀一起使用时,将具备非常清晰的含义,例如[`vec::IntoIter`].
[`vec::IntoIter`]: https://doc.rust-lang.org/std/vec/struct.IntoIter.html
### 标准库示例
* [`Vec::iter`] returns [`Iter`][slice::Iter]
* [`Vec::iter_mut`] returns [`IterMut`][slice::IterMut]
* [`Vec::into_iter`] returns [`IntoIter`][vec::IntoIter]
* [`BTreeMap::keys`] returns [`Keys`][btree_map::Keys]
* [`BTreeMap::values`] returns [`Values`][btree_map::Values]
[`Vec::iter`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter
[slice::Iter]: https://doc.rust-lang.org/std/slice/struct.Iter.html
[`Vec::iter_mut`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.iter_mut
[slice::IterMut]: https://doc.rust-lang.org/std/slice/struct.IterMut.html
[`Vec::into_iter`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_iter
[vec::IntoIter]: https://doc.rust-lang.org/std/vec/struct.IntoIter.html
[`BTreeMap::keys`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.keys
[btree_map::Keys]: https://doc.rust-lang.org/std/collections/btree_map/struct.Keys.html
[`BTreeMap::values`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.values
[btree_map::Values]: https://doc.rust-lang.org/std/collections/btree_map/struct.Values.html
<a id="c-feature"></a>
## Cargo Feature的名称不应该包含占位词(C-FEATURE)
不要在[Cargo feature]中包含无法传达任何意义的词,例如`use-abc`或`with-abc`,直接命名为`abc`即可。
[Cargo feature]: http://doc.crates.io/manifest.html#the-features-section
一个典型的例子就是:一个包对标准库有可选性的依赖。标准的写法如下:
```toml
# 在Cargo.toml中
[features]
default = ["std"]
std = []
```
```rust
// 在我们自定义的lib.rs中
#![cfg_attr(not(feature = "std"), no_std)]
```
除了`std`之外,不要使用任何`ust-std`或者`with-std`等自以为很有创造性的名称。
## 命名要使用一致性的词序(C-WORD-ORDER)
这是一些标准库中的错误类型:
- [`JoinPathsError`](https://doc.rust-lang.org/std/env/struct.JoinPathsError.html)
- [`ParseBoolError`](https://doc.rust-lang.org/std/str/struct.ParseBoolError.html)
- [`ParseCharError`](https://doc.rust-lang.org/std/char/struct.ParseCharError.html)
- [`ParseFloatError`](https://doc.rust-lang.org/std/num/struct.ParseFloatError.html)
- [`ParseIntError`](https://doc.rust-lang.org/std/num/struct.ParseIntError.html)
- [`RecvTimeoutError`](https://doc.rust-lang.org/std/sync/mpsc/enum.RecvTimeoutError.html)
- [`StripPrefixError`](https://doc.rust-lang.org/std/path/struct.StripPrefixError.html)
它们都使用了`谓语-宾语-错误`的词序,如果我们想要表达一个网络地址无法分析的错误,由于词序一致性的原则,命名应该如下`ParseAddrError`,而不是`AddrParseError`。
词序和个人习惯有很大关系,想要注意的是,你可以选择合适的词序,但是要在包的范畴内保持一致性,就如标准库中的包一样。

@ -0,0 +1,70 @@
包含了一些Iterator的常用处理方法
## 遍历同时获取元素的索引
```rust
let mut xs = vec![1i32, 2, 3];
for (i, x) in xs.iter().enumerate() {
println!("In position {} we have value {}", i, x);
}
```
## 几种从Vec生成Iterator的方式
1. iter返回的是值的不可变引用&T
2. iter_mut返回的是可变引用&mut T
3. into_iter返回的是T类型的值
```rust
let mut v = [String::from("a"), String::from("a"), String::from("a")];
// - move occurs because `v` has type `Vec<String>`, which does not implement the `Copy
//`v` moved due to this method call
for x in v.into_iter() {
println!("{:?}", x)
}
// Error: borrow of moved value: `v`
println!("{:?}", v)
```
## 忽略Vec中失败的Result
`filter_map` calls a function and filters out the results that are `None`
```rust
fn main() {
let strings = vec!["tofu", "93", "18"];
let numbers: Vec<_> = strings
.into_iter()
.filter_map(|s| s.parse::<i32>().ok())
.collect();
println!("Results: {:?}", numbers);
}
```
## 遍历Vec时失败直接返回
`Result` implements `FromIter` so that a vector of results (`Vec<Result<T, E>>`) can be turned into a result with a vector (`Result<Vec<T>, E>`). Once an `Result::Err` is found, the iteration will terminate
```rust
fn main() {
let strings = vec!["tofu", "93", "18"];
let numbers: Result<Vec<_>, _> = strings
.into_iter()
.map(|s| s.parse::<i32>())
.collect();
println!("Results: {:?}", numbers);
}
```
This same technique can be used with `Option`.
## 遍历Vec时收集所有的正确值和错误值
```rust
fn main() {
let strings = vec!["tofu", "93", "18"];
let (numbers, errors): (Vec<_>, Vec<_>) = strings
.into_iter()
.map(|s| s.parse::<i32>())
.partition(Result::is_ok);
let numbers: Vec<_> = numbers.into_iter().map(Result::unwrap).collect();
let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
println!("Numbers: {:?}", numbers);
println!("Errors: {:?}", errors);
}
```

@ -0,0 +1,2 @@
## Pin、UnPin
1. https://blog.cloudflare.com/pin-and-unpin-in-rust/

@ -0,0 +1,13 @@
## #[derive(Default)]
```rust
#[derive(Default)]
struct NotSend(Rc<()>);
fn require_send(_: impl Send) {}
async fn bar() {}
async fn foo() {
//Returns the "default value" for a type.
NotSend::default();
}
```

@ -0,0 +1,150 @@
## 读取全部内容
```rust
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
fn main() {
// Create a path to the desired file
let path = Path::new("hello.txt");
let display = path.display();
// Open the path in read-only mode, returns `io::Result<File>`
let mut file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", display, why),
Ok(file) => file,
};
// Read the file contents into a string, returns `io::Result<usize>`
let mut s = String::new();
match file.read_to_string(&mut s) {
Err(why) => panic!("couldn't read {}: {}", display, why),
Ok(_) => print!("{} contains:\n{}", display, s),
}
// `file` goes out of scope, and the "hello.txt" file gets closed
}
```
## 读取全部行
This process is more efficient than creating a String in memory especially working with larger files.
```rust
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
fn main() {
// File hosts must exist in current path before this produces output
if let Ok(lines) = read_lines("./hosts") {
// Consumes the iterator, returns an (Optional) String
for line in lines {
if let Ok(ip) = line {
println!("{}", ip);
}
}
}
}
// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
```
## 一些常用的文件操作
```rust
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::os::unix;
use std::path::Path;
fn cat(path: &Path) -> io::Result<String> {
let mut f = File::open(path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// A simple implementation of `% echo s > path`
fn echo(s: &str, path: &Path) -> io::Result<()> {
let mut f = File::create(path)?;
f.write_all(s.as_bytes())
}
// A simple implementation of `% touch path` (ignores existing files)
fn touch(path: &Path) -> io::Result<()> {
match OpenOptions::new().create(true).write(true).open(path) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
fn main() {
println!("`mkdir a`");
// Create a directory, returns `io::Result<()>`
match fs::create_dir("a") {
Err(why) => println!("! {:?}", why.kind()),
Ok(_) => {},
}
println!("`echo hello > a/b.txt`");
// The previous match can be simplified using the `unwrap_or_else` method
echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`mkdir -p a/c/d`");
// Recursively create a directory, returns `io::Result<()>`
fs::create_dir_all("a/c/d").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`touch a/c/e.txt`");
touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`ln -s ../b.txt a/c/b.txt`");
// Create a symbolic link, returns `io::Result<()>`
if cfg!(target_family = "unix") {
unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
}
println!("`cat a/c/b.txt`");
match cat(&Path::new("a/c/b.txt")) {
Err(why) => println!("! {:?}", why.kind()),
Ok(s) => println!("> {}", s),
}
println!("`ls a`");
// Read the contents of a directory, returns `io::Result<Vec<Path>>`
match fs::read_dir("a") {
Err(why) => println!("! {:?}", why.kind()),
Ok(paths) => for path in paths {
println!("> {:?}", path.unwrap().path());
},
}
println!("`rm a/c/e.txt`");
// Remove a file, returns `io::Result<()>`
fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
});
println!("`rmdir a/c/d`");
// Remove an empty directory, returns `io::Result<()>`
fs::remove_dir("a/c/d").unwrap_or_else(|why| {
println!("! {:?}", why.kind());
}
}
```

@ -0,0 +1,23 @@
## 函数的入参是一个async function
因为我们使用了trait bound所以不能用`Fn() -> impl Future<Output=Result<Return, sql::Error>>`的方式.
```rust
use core::future::Future;
pub async fn on_tran<F, Fut>(f: F) -> usize
where F: Fn() -> Fut, Fut: Future<Output=usize> {
f().await
}
#[tokio::main]
async fn main() {
let foo = || {
async {
8 as usize
}
};
println!("{}", on_tran(foo).await);
}
```

@ -0,0 +1,6 @@
## Key of hashmap
Any type that implements the Eq and Hash traits can be a key in HashMap.
Note that f32 and f64 do not implement Hash, likely because floating-point precision errors would make using them as hashmap keys horribly error-prone.
All collection classes implement Eq and Hash if their contained type also respectively implements Eq and Hash. For example, Vec<T> will implement Hash if T implements Hash.

@ -0,0 +1,29 @@
## Raw identifiers
Rust因为版本更迭原因可能会新增一些`关键字`,这些新增关键字可能会导致旧的函数名调用不再通过编译例如在Rust Edition 2015中引入了新的关键字`try`.
运行以下代码:
```rust
extern crate foo;
fn main() {
foo::try();
}
```
将获得下面的错误
```rust
error: expected identifier, found keyword `try`
--> src/main.rs:4:4
|
4 | foo::try();
| ^^^ expected identifier, found keyword
```
可以用Raw identifier来解决:
```rust
extern crate foo;
fn main() {
foo::r#try();
}
```

@ -0,0 +1,2 @@
## 容器类型说明图
https://docs.google.com/presentation/d/1q-c7UAyrUlM-eZyTo1pd8SZ0qwA_wYxmPZVOQkoDmH4/edit#slide=id.p

@ -0,0 +1,4 @@
## Reading input as Raw Bytes
The built-in String type uses UTF-8 internally, which adds a small, but nonzero overhead caused by UTF-8 validation when you read input into it. If you just want to process input bytes without worrying about UTF-8 (for example if you handle ASCII text), you can use `BufRead::read_until`.

@ -0,0 +1,38 @@
一些lifetime消除规则
### 1
Let's talk about a feature that's available in both editions: we've added some additional elision rules for `impl` blocks and function definitions. Code like this:
```rust
impl<'a> Reader for BufReader<'a> {
// methods go here
}
```
can now be written like this:
```rust
impl Reader for BufReader<'_> {
// methods go here
}
```
The `'_` lifetime still shows that `BufReader` takes a parameter, but we don't need to create a name for it anymore.
### 2
Lifetimes are still required to be defined in structs. However, we no longer require as much boilerplate as before:
```rust
// Rust 2015
struct Ref<'a, T: 'a> {
field: &'a T
}
// Rust 2018
struct Ref<'a, T> {
field: &'a T
}
```
The `: 'a` is inferred. You can still be explicit if you prefer. We're considering some more options for elision here in the future, but have no concrete plans yet.

@ -0,0 +1,205 @@
## Operators and Symbols
This appendix contains a glossary of Rusts syntax, including operators and
other symbols that appear by themselves or in the context of paths, generics,
trait bounds, macros, attributes, comments, tuples, and brackets.
### Operators
Table B-1 contains the operators in Rust, an example of how the operator would
appear in context, a short explanation, and whether that operator is
overloadable. If an operator is overloadable, the relevant trait to use to
overload that operator is listed.
<span class="caption">Table B-1: Operators</span>
| Operator | Example | Explanation | Overloadable? |
|----------|---------|-------------|---------------|
| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | |
| `!` | `!expr` | Bitwise or logical complement | `Not` |
| `!=` | `var != expr` | Nonequality comparison | `PartialEq` |
| `%` | `expr % expr` | Arithmetic remainder | `Rem` |
| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` |
| `&` | `&expr`, `&mut expr` | Borrow | |
| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer type | |
| `&` | `expr & expr` | Bitwise AND | `BitAnd` |
| `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` |
| `&&` | `expr && expr` | Short-circuiting logical AND | |
| `*` | `expr * expr` | Arithmetic multiplication | `Mul` |
| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign` |
| `*` | `*expr` | Dereference | `Deref` |
| `*` | `*const type`, `*mut type` | Raw pointer | |
| `+` | `trait + trait`, `'a + trait` | Compound type constraint | |
| `+` | `expr + expr` | Arithmetic addition | `Add` |
| `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` |
| `,` | `expr, expr` | Argument and element separator | |
| `-` | `- expr` | Arithmetic negation | `Neg` |
| `-` | `expr - expr` | Arithmetic subtraction | `Sub` |
| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` |
| `->` | `fn(...) -> type`, <code>&vert;...&vert; -> type</code> | Function and closure return type | |
| `.` | `expr.ident` | Member access | |
| `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal | `PartialOrd` |
| `..=` | `..=expr`, `expr..=expr` | Right-inclusive range literal | `PartialOrd` |
| `..` | `..expr` | Struct literal update syntax | |
| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern binding | |
| `...` | `expr...expr` | (Deprecated, use `..=` instead) In a pattern: inclusive range pattern | |
| `/` | `expr / expr` | Arithmetic division | `Div` |
| `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` |
| `:` | `pat: type`, `ident: type` | Constraints | |
| `:` | `ident: expr` | Struct field initializer | |
| `:` | `'a: loop {...}` | Loop label | |
| `;` | `expr;` | Statement and item terminator | |
| `;` | `[...; len]` | Part of fixed-size array syntax | |
| `<<` | `expr << expr` | Left-shift | `Shl` |
| `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` |
| `<` | `expr < expr` | Less than comparison | `PartialOrd` |
| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |
| `=` | `var = expr`, `ident = type` | Assignment/equivalence | |
| `==` | `expr == expr` | Equality comparison | `PartialEq` |
| `=>` | `pat => expr` | Part of match arm syntax | |
| `>` | `expr > expr` | Greater than comparison | `PartialOrd` |
| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |
| `>>` | `expr >> expr` | Right-shift | `Shr` |
| `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` |
| `@` | `ident @ pat` | Pattern binding | |
| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |
| `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` |
| <code>&vert;</code> | <code>pat &vert; pat</code> | Pattern alternatives | |
| <code>&vert;</code> | <code>expr &vert; expr</code> | Bitwise OR | `BitOr` |
| <code>&vert;=</code> | <code>var &vert;= expr</code> | Bitwise OR and assignment | `BitOrAssign` |
| <code>&vert;&vert;</code> | <code>expr &vert;&vert; expr</code> | Short-circuiting logical OR | |
| `?` | `expr?` | Error propagation | |
### Non-operator Symbols
The following list contains all non-letters that dont function as operators;
that is, they dont behave like a function or method call.
Table B-2 shows symbols that appear on their own and are valid in a variety of
locations.
<span class="caption">Table B-2: Stand-Alone Syntax</span>
| Symbol | Explanation |
|--------|-------------|
| `'ident` | Named lifetime or loop label |
| `...u8`, `...i32`, `...f64`, `...usize`, etc. | Numeric literal of specific type |
| `"..."` | String literal |
| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | Raw string literal, escape characters not processed |
| `b"..."` | Byte string literal; constructs a `[u8]` instead of a string |
| `br"..."`, `br#"..."#`, `br##"..."##`, etc. | Raw byte string literal, combination of raw and byte string literal |
| `'...'` | Character literal |
| `b'...'` | ASCII byte literal |
| <code>&vert;...&vert; expr</code> | Closure |
| `!` | Always empty bottom type for diverging functions |
| `_` | “Ignored” pattern binding; also used to make integer literals readable |
Table B-3 shows symbols that appear in the context of a path through the module
hierarchy to an item.
<span class="caption">Table B-3: Path-Related Syntax</span>
| Symbol | Explanation |
|--------|-------------|
| `ident::ident` | Namespace path |
| `::path` | Path relative to the crate root (i.e., an explicitly absolute path) |
| `self::path` | Path relative to the current module (i.e., an explicitly relative path).
| `super::path` | Path relative to the parent of the current module |
| `type::ident`, `<type as trait>::ident` | Associated constants, functions, and types |
| `<type>::...` | Associated item for a type that cannot be directly named (e.g., `<&T>::...`, `<[T]>::...`, etc.) |
| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it |
| `type::method(...)` | Disambiguating a method call by naming the type for which its defined |
| `<type as trait>::method(...)` | Disambiguating a method call by naming the trait and type |
Table B-4 shows symbols that appear in the context of using generic type
parameters.
<span class="caption">Table B-4: Generics</span>
| Symbol | Explanation |
|--------|-------------|
| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec<u8>`) |
| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., `"42".parse::<i32>()`) |
| `fn ident<...> ...` | Define generic function |
| `struct ident<...> ...` | Define generic structure |
| `enum ident<...> ...` | Define generic enumeration |
| `impl<...> ...` | Define generic implementation |
| `for<...> type` | Higher-ranked lifetime bounds |
| `type<ident=type>` | A generic type where one or more associated types have specific assignments (e.g., `Iterator<Item=T>`) |
Table B-5 shows symbols that appear in the context of constraining generic type
parameters with trait bounds.
<span class="caption">Table B-5: Trait Bound Constraints</span>
| Symbol | Explanation |
|--------|-------------|
| `T: U` | Generic parameter `T` constrained to types that implement `U` |
| `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) |
| `T: 'static` | Generic type `T` contains no borrowed references other than `'static` ones |
| `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` |
| `T: ?Sized` | Allow generic type parameter to be a dynamically sized type |
| `'a + trait`, `trait + trait` | Compound type constraint |
Table B-6 shows symbols that appear in the context of calling or defining
macros and specifying attributes on an item.
<span class="caption">Table B-6: Macros and Attributes</span>
| Symbol | Explanation |
|--------|-------------|
| `#[meta]` | Outer attribute |
| `#![meta]` | Inner attribute |
| `$ident` | Macro substitution |
| `$ident:kind` | Macro capture |
| `$(…)…` | Macro repetition |
| `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation |
Table B-7 shows symbols that create comments.
<span class="caption">Table B-7: Comments</span>
| Symbol | Explanation |
|--------|-------------|
| `//` | Line comment |
| `//!` | Inner line doc comment |
| `///` | Outer line doc comment |
| `/*...*/` | Block comment |
| `/*!...*/` | Inner block doc comment |
| `/**...*/` | Outer block doc comment |
Table B-8 shows symbols that appear in the context of using tuples.
<span class="caption">Table B-8: Tuples</span>
| Symbol | Explanation |
|--------|-------------|
| `()` | Empty tuple (aka unit), both literal and type |
| `(expr)` | Parenthesized expression |
| `(expr,)` | Single-element tuple expression |
| `(type,)` | Single-element tuple type |
| `(expr, ...)` | Tuple expression |
| `(type, ...)` | Tuple type |
| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants |
| `expr.0`, `expr.1`, etc. | Tuple indexing |
Table B-9 shows the contexts in which curly braces are used.
<span class="caption">Table B-9: Curly Brackets</span>
| Context | Explanation |
|---------|-------------|
| `{...}` | Block expression |
| `Type {...}` | `struct` literal |
Table B-10 shows the contexts in which square brackets are used.
<span class="caption">Table B-10: Square Brackets</span>
| Context | Explanation |
|---------|-------------|
| `[...]` | Array literal |
| `[expr; len]` | Array literal containing `len` copies of `expr` |
| `[type; len]` | Array type containing `len` instances of `type` |
| `expr[expr]` | Collection indexing. Overloadable (`Index`, `IndexMut`) |
| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the “index” |

@ -0,0 +1,31 @@
## layout
```go
.
├── Cargo.lock
├── Cargo.toml
├── src/
│ ├── lib.rs
│ ├── main.rs
│ └── bin/
│ ├── named-executable.rs
│ ├── another-executable.rs
│ └── multi-file-executable/
│ ├── main.rs
│ └── some_module.rs
├── benches/
│ ├── large-input.rs
│ └── multi-file-bench/
│ ├── main.rs
│ └── bench_module.rs
├── examples/
│ ├── simple.rs
│ └── multi-file-example/
│ ├── main.rs
│ └── ex_module.rs
└── tests/
├── some-integration-tests.rs
└── multi-file-test/
├── main.rs
└── test_module.rs
```

@ -0,0 +1,7 @@
## books
1. [Rust性能之书](https://nnethercote.github.io/perf-book/title-page.html)
2. [How to write fast rust code](https://likebike.com/posts/How_To_Write_Fast_Rust_Code.html#emit-asm)
## crates
1. [高性能Mutex库](https://github.com/Amanieu/parking_lot)

@ -0,0 +1,7 @@
一些关于println的技巧
## 打印对象地址
```rust
let v= vec![1,2,3];
println!("{:p}",v.as_ptr())
```

@ -0,0 +1,34 @@
## struct中的一个字段是另外一个字段的指针
```rust
#[derive(Debug)]
struct Test {
a: String,
b: *const String,
}
impl Test {
fn new(txt: &str) -> Self {
Test {
a: String::from(txt),
b: std::ptr::null(),
}
}
fn init(&mut self) {
let self_ref: *const String = &self.a;
self.b = self_ref;
}
fn a(&self) -> &str {
&self.a
}
fn b(&self) -> &String {
assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
unsafe { &*(self.b) }
}
}
```
Test provides methods to get a reference to the value of the fields a and b. Since b is a reference to a we store it as a pointer since the borrowing rules of Rust doesn't allow us to define this lifetime. We now have what we call a self-referential struct.

@ -0,0 +1,7 @@
## code snippets
1. https://stackoverflow.com/questions/67823680/open-a-single-file-from-a-zip-archive-and-pass-on-as-read-instance/67828823#67828823
## crates
1. https://github.com/Kimundi/owning-ref-rs
2. https://github.com/joshua-maros/ouroboros

@ -0,0 +1,82 @@
## 字符串常量
```rust
fn main() {
// You can use escapes to write bytes by their hexadecimal values...
let byte_escape = "I'm writing \x52\x75\x73\x74!";
println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape);
// ...or Unicode code points.
let unicode_codepoint = "\u{211D}";
let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
println!("Unicode character {} (U+211D) is called {}",
unicode_codepoint, character_name );
let long_string = "String literals
can span multiple lines.
The linebreak and indentation here ->\
<- can be escaped too!";
println!("{}", long_string);
}
```
```rust
fn main() {
let raw_str = r"Escapes don't work here: \x3F \u{211D}";
println!("{}", raw_str);
// If you need quotes in a raw string, add a pair of #s
let quotes = r#"And then I said: "There is no escape!""#;
println!("{}", quotes);
// If you need "# in your string, just use more #s in the delimiter.
// There is no limit for the number of #s you can use.
let longer_delimiter = r###"A string with "# in it. And even "##!"###;
println!("{}", longer_delimiter);
}
```
## Bytes string
Want a string that's not UTF-8? (Remember, `str` and `String` must be valid UTF-8). Or maybe you want an array of bytes that's mostly text? Byte strings to the rescue!
```rust
use std::str;
fn main() {
// Note that this is not actually a `&str`
let bytestring: &[u8; 21] = b"this is a byte string";
// Byte arrays don't have the `Display` trait, so printing them is a bit limited
println!("A byte string: {:?}", bytestring);
// Byte strings can have byte escapes...
let escaped = b"\x52\x75\x73\x74 as bytes";
// ...but no unicode escapes
// let escaped = b"\u{211D} is not allowed";
println!("Some escaped bytes: {:?}", escaped);
// Raw byte strings work just like raw strings
let raw_bytestring = br"\u{211D} is not escaped here";
println!("{:?}", raw_bytestring);
// Converting a byte array to `str` can fail
if let Ok(my_str) = str::from_utf8(raw_bytestring) {
println!("And the same as text: '{}'", my_str);
}
let _quotes = br#"You can also use "fancier" formatting, \
like with normal raw strings"#;
// Byte strings don't have to be UTF-8
let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // "ようこそ" in SHIFT-JIS
// But then they can't always be converted to `str`
match str::from_utf8(shift_jis) {
Ok(my_str) => println!("Conversion successful: '{}'", my_str),
Err(e) => println!("Conversion failed: {:?}", e),
};
}
```

@ -0,0 +1,71 @@
关于调用os的命令
```rust
use std::process::Command;
fn main() {
let output = Command::new("rustc")
.arg("--versn")
.output().unwrap_or_else(|e| {
panic!("failed to execute process: {}", e)
});
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout);
print!("rustc succeeded and stdout was:\n{}", s);
} else {
let s = String::from_utf8_lossy(&output.stderr);
print!("rustc failed and stderr was:\n{}", s);
}
}
```
## Pipes
The std::Child struct represents a running child process, and exposes the stdin, stdout and stderr handles for interaction with the underlying process via pipes.
```rust
use std::io::prelude::*;
use std::process::{Command, Stdio};
static PANGRAM: &'static str =
"the quick brown fox jumped over the lazy dog\n";
fn main() {
// Spawn the `wc` command
let process = match Command::new("wc")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn() {
Err(why) => panic!("couldn't spawn wc: {}", why),
Ok(process) => process,
};
// Write a string to the `stdin` of `wc`.
//
// `stdin` has type `Option<ChildStdin>`, but since we know this instance
// must have one, we can directly `unwrap` it.
match process.stdin.unwrap().write_all(PANGRAM.as_bytes()) {
Err(why) => panic!("couldn't write to wc stdin: {}", why),
Ok(_) => println!("sent pangram to wc"),
}
// Because `stdin` does not live after the above calls, it is `drop`ed,
// and the pipe is closed.
//
// This is very important, otherwise `wc` wouldn't start processing the
// input we just sent.
// The `stdout` field also has type `Option<ChildStdout>` so must be unwrapped.
let mut s = String::new();
match process.stdout.unwrap().read_to_string(&mut s) {
Err(why) => panic!("couldn't read wc stdout: {}", why),
Ok(_) => print!("wc responded with:\n{}", s),
}
}
```

@ -0,0 +1,85 @@
## Documentation testing
The primary way of documenting a Rust project is through annotating the source code. Documentation comments are written in markdown and support code blocks in them. Rust takes care about correctness, so these code blocks are compiled and used as tests.
```rust
/// First line is a short summary describing function.
///
/// The next lines present detailed documentation. Code blocks start with
/// triple backquotes and have implicit `fn main()` inside
/// and `extern crate <cratename>`. Assume we're testing `doccomments` crate:
///
/// ```
/// let result = doccomments::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
/// Usually doc comments may include sections "Examples", "Panics" and "Failures".
///
/// The next function divides two numbers.
///
/// # Examples
///
/// ```
/// let result = doccomments::div(10, 2);
/// assert_eq!(result, 5);
/// ```
///
/// # Panics
///
/// The function panics if the second argument is zero.
///
/// ```rust,should_panic
/// // panics on division by zero
/// doccomments::div(10, 0);
/// ```
pub fn div(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Divide-by-zero error");
}
a / b
}
/// Using hidden `try_main` in doc tests.
///
/// ```
/// # // hidden lines start with `#` symbol, but they're still compileable!
/// # fn try_main() -> Result<(), String> { // line that wraps the body shown in doc
/// let res = try::try_div(10, 2)?;
/// # Ok(()) // returning from try_main
/// # }
/// # fn main() { // starting main that'll unwrap()
/// # try_main().unwrap(); // calling try_main and unwrapping
/// # // so that test will panic in case of error
/// # }
/// ```
pub fn try_div(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Divide-by-zero"))
} else {
Ok(a / b)
}
}
```
```bash
$ cargo test
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests doccomments
running 3 tests
test src/lib.rs - add (line 7) ... ok
test src/lib.rs - div (line 21) ... ok
test src/lib.rs - div (line 31) ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```
## 最新进展
根据twitter上的消息rust即将支持从测试文件中自动获取文档注释的功能这样就能保持测试文件和文档的一致性无需在多个地方维护多套测试代码

@ -0,0 +1,19 @@
Cargo looks for integration tests in `tests` directory next to `src`.
File `src/lib.rs`:
```rust
// Define this in a crate called `adder`.
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
```
File with `test: tests/integration_test.rs`:
```rust
#[test]
fn test_add() {
assert_eq!(adder::add(3, 2), 5);
}
```

@ -0,0 +1,34 @@
## Development dependencies
Sometimes there is a need to have dependencies for tests (or examples, or benchmarks) only. Such dependencies are added to Cargo.toml in the [dev-dependencies] section. These dependencies are not propagated to other packages which depend on this package.
One such example is using a crate that extends standard assert! macros.
File Cargo.toml:
```toml
# standard crate data is left out
[dev-dependencies]
pretty_assertions = "0.4.0"
```
File `src/lib.rs`:
```toml
// externing crate for test-only use
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}
```

@ -0,0 +1,92 @@
## Tests and ?
in Rust 2018, your unit tests can return Result<()>, which lets you use ? in them! This can make them much more concise.
```rust
fn sqrt(number: f64) -> Result<f64, String> {
if number >= 0.0 {
Ok(number.powf(0.5))
} else {
Err("negative floats don't have square roots".to_owned())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sqrt() -> Result<(), String> {
let x = 4.0;
assert_eq!(sqrt(x)?.powf(2.0), x);
Ok(())
}
}
```
## Testing panics
To check functions that should panic under certain circumstances, use attribute #[should_panic]. This attribute accepts optional parameter expected = with the text of the panic message. If your function can panic in multiple ways, it helps make sure your test is testing the correct panic.
```rust
pub fn divide_non_zero_result(a: u32, b: u32) -> u32 {
if b == 0 {
panic!("Divide-by-zero error");
} else if a < b {
panic!("Divide result is zero");
}
a / b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_divide() {
assert_eq!(divide_non_zero_result(10, 2), 5);
}
#[test]
#[should_panic]
fn test_any_panic() {
divide_non_zero_result(1, 0);
}
#[test]
#[should_panic(expected = "Divide result is zero")]
fn test_specific_panic() {
divide_non_zero_result(1, 10);
}
}
```
## Ignoring tests
Tests can be marked with the #[ignore] attribute to exclude some tests. Or to run them with command cargo test -- --ignored
```rust
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 2), 4);
}
#[test]
fn test_add_hundred() {
assert_eq!(add(100, 2), 102);
assert_eq!(add(2, 100), 102);
}
#[test]
#[ignore]
fn ignored_test() {
assert_eq!(add(0, 0), 0);
}
}
```

@ -0,0 +1,27 @@
## Arc和Mutex结合实现多线程数据修改和汇总
```rust
use std::sync::{Arc,Mutex};
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = Arc::clone(&status);
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
let mut s = status_shared.lock().unwrap();
s.jobs_completed += 1;
}
});
while status.lock().unwrap().jobs_completed < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
```

@ -0,0 +1,10 @@
## unknown `into` behavior
```rust
let s: Box<dyn Error + Send + Sync> = "connection reset by peer".into();
```
this works because:
```rust
impl From<&'_ str> for Box<dyn Error>
```
Loading…
Cancel
Save