From f577ec7dafd4dc6f69c4d04f9fb8fb0b3a199d2b Mon Sep 17 00:00:00 2001 From: l00556901 Date: Fri, 3 Dec 2021 16:22:43 +0800 Subject: [PATCH] string control collection --- .../coding_practice/collections.md | 18 +- .../coding_practice/control-flow.md | 422 ++++++++---------- src/safe-guides/coding_practice/strings.md | 183 ++++---- 3 files changed, 289 insertions(+), 334 deletions(-) diff --git a/src/safe-guides/coding_practice/collections.md b/src/safe-guides/coding_practice/collections.md index 63603738..8db650e7 100644 --- a/src/safe-guides/coding_practice/collections.md +++ b/src/safe-guides/coding_practice/collections.md @@ -54,13 +54,17 @@ Rust 标准库内置的集合类型,在安全和性能方面还是比较靠谱 -## G.CLT.01 非必要情况下,不要使用 `LinkedList`,而用 `Vec`或`VecDeque` 代替 +## G.CLT.01 非必要情况下,不要使用`LinkedList`,而用`Vec`或`VecDeque`代替 -### 【级别:建议】 +**【级别】** 建议 -建议按此规范执行。 +**【描述】** + +一般情况下,有 `Vec`和`VecDeque` 性能更好。`LinkedList` 存在内存浪费,缓存局部性(Cache Locality)比较差,无法更好地利用CPU 缓存机制,性能很差。 + +只有在有大量的 列表 拆分 和 合并 操作时,才真正需要链表,因为链表允许你只需操作指针而非复制数据来完成这些操作。 -### 【Lint 检测】 +**【Lint 检测】** | lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | | ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | @@ -73,11 +77,5 @@ Rust 标准库内置的集合类型,在安全和性能方面还是比较靠谱 avoid-breaking-exported-api=true ``` -### 【描述】 - -一般情况下,有 `Vec`和`VecDeque` 性能更好。`LinkedList` 存在内存浪费,缓存局部性(Cache Locality)比较差,无法更好地利用CPU 缓存机制,性能很差。 - -只有在有大量的 列表 拆分 和 合并 操作时,才真正需要链表,因为链表允许你只需操作指针而非复制数据来完成这些操作。 - diff --git a/src/safe-guides/coding_practice/control-flow.md b/src/safe-guides/coding_practice/control-flow.md index f15d11f4..0f78acca 100644 --- a/src/safe-guides/coding_practice/control-flow.md +++ b/src/safe-guides/coding_practice/control-flow.md @@ -2,8 +2,7 @@ # 控制流程 -Rust 中 流程控制 也是属于 表达式,但在本规范中将其独立出来。 - +Rust中流程控制也是属于表达式,但在本规范中将其独立出来。 --- @@ -13,45 +12,7 @@ Rust 中 流程控制 也是属于 表达式,但在本规范中将其独立出 迭代器虽然是 Rust 中比较推崇的方式,但也没必要过度使用它。总之,如果使用迭代器让代码太复杂,就考虑换个非迭代器的方式实现吧。 -【正例】 - -创建一个 Matrix变换的函数,使用命令式风格,代码功能比较明确,更加直观。 - -```rust -// From: https://adventures.michaelfbryan.com/posts/rust-best-practices/bad-habits/#overusing-iterators -pub fn imperative_blur(input: &Matrix) -> Matrix { - assert!(input.width >= 3); - assert!(input.height >= 3); - - // allocate our output matrix, copying from the input so - // we don't need to worry about the edge cases. - let mut output = input.clone(); - - for y in 1..(input.height - 1) { - for x in 1..(input.width - 1) { - let mut pixel_value = 0.0; - - pixel_value += input[[x - 1, y - 1]]; - pixel_value += input[[x, y - 1]]; - pixel_value += input[[x + 1, y - 1]]; - - pixel_value += input[[x - 1, y]]; - pixel_value += input[[x, y]]; - pixel_value += input[[x + 1, y]]; - - pixel_value += input[[x - 1, y + 1]]; - pixel_value += input[[x, y + 1]]; - pixel_value += input[[x + 1, y + 1]]; - - output[[x, y]] = pixel_value / 9.0; - } - } - - output -} -``` - -【反例】 +**【反例】** 创建一个 Matrix变换的函数,但是这种迭代器的方式,代码可读性相比于命令式更困难。 @@ -114,25 +75,53 @@ fn blur_rows<'a>( } ``` -## P.CTL.02 优先使用模式匹配而不是 `if` 判断值是否相等 +**【正例】** -**【描述】** +创建一个 Matrix变换的函数,使用命令式风格,代码功能比较明确,更加直观。 -Rust 中 模式匹配 是惯用法,而不是通过 `if` 判断值是否相等。 +```rust +// From: https://adventures.michaelfbryan.com/posts/rust-best-practices/bad-habits/#overusing-iterators +pub fn imperative_blur(input: &Matrix) -> Matrix { + assert!(input.width >= 3); + assert!(input.height >= 3); -【正例】 + // allocate our output matrix, copying from the input so + // we don't need to worry about the edge cases. + let mut output = input.clone(); -```rust -if let Some(value) = opt { - ... -} -// or -if let [first, ..] = list { - ... + for y in 1..(input.height - 1) { + for x in 1..(input.width - 1) { + let mut pixel_value = 0.0; + + pixel_value += input[[x - 1, y - 1]]; + pixel_value += input[[x, y - 1]]; + pixel_value += input[[x + 1, y - 1]]; + + pixel_value += input[[x - 1, y]]; + pixel_value += input[[x, y]]; + pixel_value += input[[x + 1, y]]; + + pixel_value += input[[x - 1, y + 1]]; + pixel_value += input[[x, y + 1]]; + pixel_value += input[[x + 1, y + 1]]; + + output[[x, y]] = pixel_value / 9.0; + } + } + + output } ``` -【反例】 + + +## P.CTL.02 优先使用模式匹配而不是`if`判断值是否相等 + +**【描述】** + +Rust 中 模式匹配 是惯用法,而不是通过 `if` 判断值是否相等。 + +**【反例】** ```rust let opt: Option<_> = ...; @@ -152,215 +141,217 @@ if let [first, ..] = list { ``` +**【正例】** - - - - +```rust +if let Some(value) = opt { + ... +} +// or +if let [first, ..] = list { + ... +} +``` --- -## G.CTL.01 避免在流程控制分支中使用重复代码 - -### 【级别:建议】 +## G.CTL.01 避免在流程控制分支中使用重复代码 -建议按此规范执行。 +**【级别】** 建议 -### 【Lint 检测】 - -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------ | ---- | --------- | ------ | ------ | -| [branches_sharing_code](https://rust-lang.github.io/rust-clippy/master/#branches_sharing_code) | yes| no | nursery | allow | +**【描述】** -### 【描述】 +略 -【正例】 +**【反例】** ```rust -println!("Hello World"); let foo = if … { + println!("Hello World"); 13 } else { + println!("Hello World"); 42 }; ``` -【反例】 +**【正例】** ```rust +println!("Hello World"); let foo = if … { - println!("Hello World"); 13 } else { - println!("Hello World"); 42 }; ``` -## G.CTL.02 控制流程的分支逻辑要保持精炼 +**【Lint 检测】** -### 【级别:建议】 +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------ | ---- | --------- | ------ | ------ | +| [branches_sharing_code](https://rust-lang.github.io/rust-clippy/master/#branches_sharing_code) | yes| no | nursery | allow | -建议按此规范执行。 -### 【Lint 检测】 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | -------------- | ----- | -| [collapsible_else_if](https://rust-lang.github.io/rust-clippy/master/#collapsible_else_if) | yes | no | style | warn | -| [collapsible_if](https://rust-lang.github.io/rust-clippy/master/#collapsible_if) | yes | no | style | warn | -| [collapsible_match](https://rust-lang.github.io/rust-clippy/master/#collapsible_match) | yes | no | style | warn | -| [double_comparisons](https://rust-lang.github.io/rust-clippy/master/#double_comparisons) | yes | no | **complexity** | warn | -| [wildcard_in_or_patterns](https://rust-lang.github.io/rust-clippy/master/#wildcard_in_or_patterns) | yes | no | **complexity** | warn | +## G.CTL.02 控制流程的分支逻辑要保持精炼 + +**【级别】** 建议 -### 【描述】 +**【描述】** -【正例】 +略 + +**【反例】** ```rust -// else if + if x { … -} else if y { - … +} else { // collapsible_else_if + if y { + … + } } -// Merge multiple conditions -if x && y { - … +if x { // collapsible_if + if y { + … + } } -// match +// collapsible_match fn func(opt: Option>) { let n = match opt { - Some(Ok(n)) => n, - _ => return, + Some(n) => match n { + Ok(n) => n, + _ => return, + } + None => return, }; } -// comparisons +// double_comparisons # let x = 1; # let y = 2; -if x <= y {} +if x == y || x < y {} // wildcard_in_or_patterns match "foo" { "a" => {}, - _ => {}, + "bar" | _ => {}, } + ``` -【反例】 +**【正例】** ```rust - +// else if if x { … -} else { // collapsible_else_if - if y { - … - } +} else if y { + … } -if x { // collapsible_if - if y { - … - } +// Merge multiple conditions +if x && y { + … } -// collapsible_match +// match fn func(opt: Option>) { let n = match opt { - Some(n) => match n { - Ok(n) => n, - _ => return, - } - None => return, + Some(Ok(n)) => n, + _ => return, }; } -// double_comparisons +// comparisons # let x = 1; # let y = 2; -if x == y || x < y {} +if x <= y {} // wildcard_in_or_patterns match "foo" { "a" => {}, - "bar" | _ => {}, + _ => {}, } - ``` -## G.CTL.03 当需要通过多个`if`判断来比较大小来区分不同情况时,优先使用`match` 和 `cmp` 来代替 if 表达式 +**【Lint 检测】** + +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | -------------- | ----- | +| [collapsible_else_if](https://rust-lang.github.io/rust-clippy/master/#collapsible_else_if) | yes | no | style | warn | +| [collapsible_if](https://rust-lang.github.io/rust-clippy/master/#collapsible_if) | yes | no | style | warn | +| [collapsible_match](https://rust-lang.github.io/rust-clippy/master/#collapsible_match) | yes | no | style | warn | +| [double_comparisons](https://rust-lang.github.io/rust-clippy/master/#double_comparisons) | yes | no | **complexity** | warn | +| [wildcard_in_or_patterns](https://rust-lang.github.io/rust-clippy/master/#wildcard_in_or_patterns) | yes | no | **complexity** | warn | -### 【级别:建议】 -建议按此规范执行。 -### 【Lint 检测】 +## G.CTL.03 当需要通过多个`if`判断来比较大小来区分不同情况时,优先使用`match`和`cmp`来代替`if`表达式 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [comparison_chain](https://rust-lang.github.io/rust-clippy/master/#comparison_chain) | yes | no | style | warn | +**【级别】** 建议 -### 【描述】 +**【描述】** 在使用多个`if-else`来对不同情况进行区分时,使用 `match` 和 `cmp` 代替 `if` 的好处是语义更加明确,而且也能帮助开发者穷尽所有可能性。 但是这里需要注意这里使用 `match` 和 `cmp` 的性能要低于 `if`表达式,因为 一般的 `>` 或 `<` 等比较操作是内联的,而 `cmp`方法没有内联。 根据实际情况来选择是否设置 `comparison_chain` 为 `allow`。 -【正例】 +**【反例】** ```rust -use std::cmp::Ordering; # fn a() {} # fn b() {} # fn c() {} fn f(x: u8, y: u8) { - match x.cmp(&y) { - Ordering::Greater => a(), - Ordering::Less => b(), - Ordering::Equal => c() - } + if x > y { + a() + } else if x < y { + b() + } else { + c() + } } ``` -【反例】 +**【正例】** ```rust +use std::cmp::Ordering; # fn a() {} # fn b() {} # fn c() {} fn f(x: u8, y: u8) { - if x > y { - a() - } else if x < y { - b() - } else { - c() - } + match x.cmp(&y) { + Ordering::Greater => a(), + Ordering::Less => b(), + Ordering::Equal => c() + } } ``` +**【Lint 检测】** +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | +| [comparison_chain](https://rust-lang.github.io/rust-clippy/master/#comparison_chain) | yes | no | style | warn | -## G.CTL.04 `if` 条件表达式分支中如果包含了 `else if` 分支也应该包含 `else` 分支 -### 【级别:建议】 -建议按此规范执行。 +## G.CTL.04 `if`条件表达式分支中如果包含了`else if`分支也应该包含`else`分支 -### 【Lint 检测】 +**【级别】** 建议 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | --------------- | ----- | -| [else_if_without_else](https://rust-lang.github.io/rust-clippy/master/#else_if_without_else) | yes | no | **restriction** | allow | +**【描述】** -### 【描述】 +略 -【正例】 +**【反例】** ```rust # fn a() {} @@ -370,12 +361,10 @@ if x.is_positive() { a(); } else if x.is_negative() { b(); -} else { - // We don't care about zero. } ``` -【反例】 +**【正例】** ```rust # fn a() {} @@ -385,33 +374,30 @@ if x.is_positive() { a(); } else if x.is_negative() { b(); +} else { + // We don't care about zero. } ``` -## G.CTL.05 如果要通过 `if` 条件表达式来判断是否panic,请优先使用断言 +【Lint 检测】** -### 【级别:建议】 +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | --------------- | ----- | +| [else_if_without_else](https://rust-lang.github.io/rust-clippy/master/#else_if_without_else) | yes | no | **restriction** | allow | -建议按此规范执行。 -### 【Lint 检测】 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [if_then_panic](https://rust-lang.github.io/rust-clippy/master/#if_then_panic) | yes | no | Style |warn| +## G.CTL.05 如果要通过 `if` 条件表达式来判断是否panic,请优先使用断言 -### 【描述】 +**【级别】** 建议 -【正例】 +**【描述】** -```rust -let sad_people: Vec<&str> = vec![]; -assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); -``` +略 -【反例】 +**【反例】** ```rust let sad_people: Vec<&str> = vec![]; @@ -420,54 +406,32 @@ if !sad_people.is_empty() { } ``` -## G.CTL.06 善用标准库中提供的迭代器适配器方法来满足自己的需求 +**【正例】** -### 【级别:建议】 - -建议按此规范执行。 +```rust +let sad_people: Vec<&str> = vec![]; +assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); +``` -### 【Lint 检测】 +**【Lint 检测】** | lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | | ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [explicit_counter_loop](https://rust-lang.github.io/rust-clippy/master/#explicit_counter_loop) | yes | no | complexity | warn | -| [filter_map_identity](https://rust-lang.github.io/rust-clippy/master/#filter_map_identity) | yes | no | complexity | warn | -| [filter_next](https://rust-lang.github.io/rust-clippy/master/#filter_next) | yes | no | complexity | warn | -| [flat_map_identity](https://rust-lang.github.io/rust-clippy/master/#flat_map_identity) | yes | no | complexity | warn | -| [flat_map_option](https://rust-lang.github.io/rust-clippy/master/#flat_map_option) | yes | no | pedantic | allow | +| [if_then_panic](https://rust-lang.github.io/rust-clippy/master/#if_then_panic) | yes | no | Style |warn| -### 【描述】 -Rust 标准库中提供了很多迭代器方法,要学会使用它们,选择合适的方法来满足自己的需求。 -下面示例中,反例中的迭代器适配器方法,都可以用对应的正例中的方法代替。 +## G.CTL.06 善用标准库中提供的迭代器适配器方法来满足自己的需求 -【正例】 +**【级别】** 建议 -```rust -// explicit_counter_loop -let v = vec![1]; -fn bar(bar: usize, baz: usize) {} -for (i, item) in v.iter().enumerate() { bar(i, *item); } - -// filter_map_identity -let iter = vec![Some(1)].into_iter(); -iter.flatten(); - -// filter_next -let vec = vec![1]; -vec.iter().find(|x| **x == 0); - -// flat_map_identity -let iter = vec![vec![0]].into_iter(); -iter.flatten(); +**【描述】** -// flat_map_option -let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); +Rust 标准库中提供了很多迭代器方法,要学会使用它们,选择合适的方法来满足自己的需求。 -``` +下面示例中,反例中的迭代器适配器方法,都可以用对应的正例中的方法代替。 -【反例】 +**【反例】** ```rust // explicit_counter_loop @@ -495,41 +459,37 @@ iter.flat_map(|x| x); let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); ``` +**【正例】** +```rust +// explicit_counter_loop +let v = vec![1]; +fn bar(bar: usize, baz: usize) {} +for (i, item) in v.iter().enumerate() { bar(i, *item); } +// filter_map_identity +let iter = vec![Some(1)].into_iter(); +iter.flatten(); +// filter_next +let vec = vec![1]; +vec.iter().find(|x| **x == 0); +// flat_map_identity +let iter = vec![vec![0]].into_iter(); +iter.flatten(); +// flat_map_option +let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); +``` +**【Lint 检测】** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | +| [explicit_counter_loop](https://rust-lang.github.io/rust-clippy/master/#explicit_counter_loop) | yes | no | complexity | warn | +| [filter_map_identity](https://rust-lang.github.io/rust-clippy/master/#filter_map_identity) | yes | no | complexity | warn | +| [filter_next](https://rust-lang.github.io/rust-clippy/master/#filter_next) | yes | no | complexity | warn | +| [flat_map_identity](https://rust-lang.github.io/rust-clippy/master/#flat_map_identity) | yes | no | complexity | warn | +| [flat_map_option](https://rust-lang.github.io/rust-clippy/master/#flat_map_option) | yes | no | pedantic | allow | diff --git a/src/safe-guides/coding_practice/strings.md b/src/safe-guides/coding_practice/strings.md index 93f65b29..1b6eb193 100644 --- a/src/safe-guides/coding_practice/strings.md +++ b/src/safe-guides/coding_practice/strings.md @@ -23,25 +23,26 @@ Rust 字符串类型众多,但本节内容主要围绕 :`String` / `&str` 预分配足够的容量,避免后续内存分配,可以提升代码性能。 -【正例】 +**【反例】** ```rust -let mut output = String::with_capacity(input.len()); +let mut output = String::new(); ``` -【反例】 +**【正例】** ```rust -let mut output = String::new(); +let mut output = String::with_capacity(input.len()); ``` -## P.STR.03 可以使用 `Cow` 来代替直接使用字符串,它可以减少 Copy + +## P.STR.03 可以使用`Cow`来代替直接使用字符串,它可以减少Copy **【描述】** 使用 `Cow` 作为字符串处理函数参数和返回值,可以尽可能地减少数据Copy 和 内存分配。当字符串没有修改的时候,实际使用的是 `&'a str`,只有当数据修改的时候才会使用`String`。对于读操作大于写操作的场景,使用 `Cow` 比较合适。 -【正例】 +**【示例】** ```rust // 对输入的字符串进行转义 @@ -72,7 +73,7 @@ pub fn naive<'a, S: Into>>(input: S) -> Cow<'a, str> { -## P.STR.04 在使用内建字符串处理函数或方法的时候,应该注意避免隐藏的嵌套迭代 或 多次迭代 +## P.STR.04 在使用内建字符串处理函数或方法的时候,应该注意避免隐藏的嵌套迭代或多次迭代 **【描述】** @@ -80,7 +81,7 @@ pub fn naive<'a, S: Into>>(input: S) -> Cow<'a, str> { 所以,在使用内建函数的时候要注意它的实现,选择合适的函数或方法,来避免这类问题。 -【正例】 +**【示例】** ```rust // 对输入的字符串进行转义 @@ -117,7 +118,7 @@ pub fn find<'a, S: Into>>(input: S) -> Cow<'a, str> { -## P.STR.05 只有在合适的场景下,才使用第三方库正则表达式`regex` +## P.STR.05 只有在合适的场景下,才使用第三方库正则表达式`regex` **【描述】** @@ -126,13 +127,14 @@ pub fn find<'a, S: Into>>(input: S) -> Cow<'a, str> { 1. 不在乎编译文件大小。`regex` 正则引擎是第三方库,引入它的时候意味着还会引入其他依赖,对编译文件大小有要求可以考虑,是否使用 `Cow` 和 内建函数方法来替代。 2. 对字符串查找性能有极致需求。`regex` 的 `find` 实现性能很好,但是 `replace` 替换就不一定了。对于替换需求,在适合 `Cow` 的场景下,使用 `Cow` 和 内建函数方法来替代 regex 可能更好。 -## P.STR.06 在拼接字符串时,建议使用 `format!` + +## P.STR.06 在拼接字符串时,建议使用`format!` **【描述】** 在Rust中有很多方法可以连接字符串,不同的连接方法适用于不同的场景,性能也会有所差别。 -【正例】 +**【示例】** ```rust // 组合字符串是最简单和直观的方法,尤其是在字符串和非字符串混合的情况下。 @@ -195,29 +197,15 @@ pub fn find<'a, S: Into>>(input: S) -> Cow<'a, str> { +## G.STR.01 在实现`Display`trait 时不要调用`to_string()`方法 +**【级别】** 建议 ---- - - - -## G.STR.01 在实现 `Display` trait 时不要调用 `to_string()` 方法 - -### 【级别:建议】 - -建议按此规范执行。 - -### 【Lint 检测】 - -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [to_string_in_display](https://rust-lang.github.io/rust-clippy/master/#to_string_in_display) | yes | no | correctness | deny | - -### 【描述】 +**【描述】** 因为 `to_string` 是间接通过 `Display` 来实现的,如果实现 `Display` 的时候再使用 `to_tring` 的话,将会无限递归。 -【正例】 +**【反例】** ```rust use std::fmt; @@ -225,12 +213,12 @@ use std::fmt; struct Structure(i32); impl fmt::Display for Structure { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) + write!(f, "{}", self.to_string()) } } ``` -【反例】 +**【正例】** ```rust use std::fmt; @@ -238,131 +226,141 @@ use std::fmt; struct Structure(i32); impl fmt::Display for Structure { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string()) + write!(f, "{}", self.0) } } ``` -## G.STR.02 在追加字符串时使用 `push_str`方法可读性更强 +**【Lint 检测】** -### 【级别:建议】 +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | +| [to_string_in_display](https://rust-lang.github.io/rust-clippy/master/#to_string_in_display) | yes | no | correctness | deny | -建议按此规范执行。 -### 【Lint 检测】 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ----------- | ----- | -| [string_add_assign](https://rust-lang.github.io/rust-clippy/master/#string_add_assign) | yes | no | pedantic | allow | -| [string_add](https://rust-lang.github.io/rust-clippy/master/#string_add) | yes | no | restriction | allow | +## G.STR.02 在追加字符串时使用`push_str`方法可读性更强 -### 【描述】 +**【级别】** 建议 + +**【描述】** -【正例】 +略 + +**【反例】** ```rust let mut x = "Hello".to_owned(); - -// More readable -x += ", World"; -x.push_str(", World"); +x = x + ", World"; ``` -【反例】 +**【正例】** ```rust let mut x = "Hello".to_owned(); -x = x + ", World"; -``` +// More readable +x += ", World"; +x.push_str(", World"); +``` +**【Lint 检测】** -## G.STR.03 将只包含 `ASCII`字符的字符串字面量转为字节序列可以直接使用`b"str"` 语法代替调用`as_bytes`方法 +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ----------- | ----- | +| [string_add_assign](https://rust-lang.github.io/rust-clippy/master/#string_add_assign) | yes | no | pedantic | allow | +| [string_add](https://rust-lang.github.io/rust-clippy/master/#string_add) | yes | no | restriction | allow | -### 【级别:建议】 -建议按此规范执行。 -### 【Lint 检测】 +## G.STR.03 将只包含 `ASCII`字符的字符串字面量转为字节序列可以直接使用`b"str"` 语法代替调用`as_bytes`方法 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [string_lit_as_bytes](https://rust-lang.github.io/rust-clippy/master/#string_lit_as_bytes) | yes | no | nursery | allow | +**【级别】** 建议 -### 【描述】 +**【描述】** 这是为了增强可读性,让代码更简洁。 注意,`"str".as_bytes()` 并不等价于 `b"str"`,而是等价于 `&b"str"[..]` 。 -【正例】 +**【反例】** ```rust -let bs = b"a byte string"; +let bs = "a byte string".as_bytes(); ``` -【反例】 +**【正例】** ```rust -let bs = "a byte string".as_bytes(); +let bs = b"a byte string"; ``` -## G.STR.04 需要判断字符串以哪个字符开头或结尾时,不要按字符迭代比较 +**【Lint 检测】** + +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | +| [string_lit_as_bytes](https://rust-lang.github.io/rust-clippy/master/#string_lit_as_bytes) | yes | no | nursery | allow | -### 【级别:建议】 -建议按此规范执行。 -### 【Lint 检测】 +## G.STR.04 需要判断字符串以哪个字符开头或结尾时,不要按字符迭代比较 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | -| [chars_last_cmp](https://rust-lang.github.io/rust-clippy/master/#chars_last_cmp) | yes | no | style | warn | -| [chars_next_cmp](https://rust-lang.github.io/rust-clippy/master/#chars_next_cmp) | yes | no | style | warn | +**【级别】** 建议 -### 【描述】 +**【描述】** Rust 语言 核心库 和 标准库都对字符串内置了一些方便的方法来处理这类需求。 迭代字符的性能虽然也很快(对500多个字符迭代转义处理大概需要4.5微秒左右),但这种场景用迭代的话,代码可读性更差一些。 -【正例】 +**【反例】** ```rust let name = "_"; -name.ends_with('_') || name.ends_with('-'); +name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); let name = "foo"; -if name.starts_with('_') {}; +if name.chars().next() == Some('_') {}; ``` - 【反例】 +**【正例】** ```rust let name = "_"; -name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); +name.ends_with('_') || name.ends_with('-'); let name = "foo"; -if name.chars().next() == Some('_') {}; +if name.starts_with('_') {}; ``` -## G.STR.05 对字符串按指定位置进行切片的时候需要小心破坏其 UTF-8 编码 +**【Lint 检测】** -### 【级别:建议】 +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ---------- | ----- | +| [chars_last_cmp](https://rust-lang.github.io/rust-clippy/master/#chars_last_cmp) | yes | no | style | warn | +| [chars_next_cmp](https://rust-lang.github.io/rust-clippy/master/#chars_next_cmp) | yes | no | style | warn | -建议按此规范执行。 -### 【Lint 检测】 -| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | -| ------------------------------------------------------------ | ------------- | ------------ | ----------- | ----- | -| [string_slice](https://rust-lang.github.io/rust-clippy/master/#string_slice) | yes | no | restriction | allow | +## G.STR.05 对字符串按指定位置进行切片的时候需要小心破坏其 UTF-8 编码 -### 【描述】 +**【级别】** 建议 + +**【描述】** 字符串默认是合法的 `UTF-8`字节序列,如果通过指定索引位置来对字符串进行切片,有可能破坏其合法 `UTF-8` 编码,除非这个位置是确定的,比如按 `char_indices` 方法来定位是合法的。 -【正例】 +**【反例】** + +```rust +let s = "Ölkanne"; +// thread 'main' panicked at 'byte index 1 is not a char boundary; +// it is inside 'Ö' (bytes 0..2) of `Ölkanne`' +let sub_s = &s[1..]; +// println!("{:?}", sub_s); +``` + +**【正例】** ```rust let s = "Ölkanne"; @@ -374,13 +372,12 @@ let sub_s = &s[pos..]; assert_eq!("lkanne", sub_s); ``` -【反例】 +**【Lint 检测】** + +| lint name | Clippy 可检测 | Rustc 可检测 | Lint Group | level | +| ------------------------------------------------------------ | ------------- | ------------ | ----------- | ----- | +| [string_slice](https://rust-lang.github.io/rust-clippy/master/#string_slice) | yes | no | restriction | allow | + + -```rust -let s = "Ölkanne"; -// thread 'main' panicked at 'byte index 1 is not a char boundary; -// it is inside 'Ö' (bytes 0..2) of `Ölkanne`' -let sub_s = &s[1..]; -// println!("{:?}", sub_s); -```