Rustfmt: 格式化修复

摘要

  • 修复各种格式化场景。

详情

2024 风格版本引入了对各种格式化场景的几项修复。

不要对齐项后或块末尾不相关的尾随注释

以前,rustfmt 会假定跟随带有尾随注释的项的行上的注释应该缩进以匹配尾随注释。现在已更改为这些注释不缩进。

风格版本 2021

pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast
                                                 // Multicast using broadcst. add.

pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE
pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE
pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX
                                   //const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX
                                   //const SQ_GRANT: u16 = 0x0012;  // GRANT
                                   //const SQ_REVOKE: u16 = 0x0013; // REVOKE

fn foo() {
    let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem.
                   // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis
                   // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at
    let b = baz();

    let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]
                                                                   // TODO(emilio): It may make sense to make this range [.01, 10.0], to align
                                                                   // with css-fonts-4's range of [1, 1000].
}

风格版本 2024

pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast
// Multicast using broadcst. add.

pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE
pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE
pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX
//const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX
//const SQ_GRANT: u16 = 0x0012;  // GRANT
//const SQ_REVOKE: u16 = 0x0013; // REVOKE

fn foo() {
    let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem.
    // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis
    // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at
    let b = baz();

    let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]
    // TODO(emilio): It may make sense to make this range [.01, 10.0], to align
    // with css-fonts-4's range of [1, 1000].
}

不要缩进注释中的字符串

以前,rustfmt 会错误地尝试格式化注释中的字符串。

原始

pub fn main() {
    /*   let s = String::from(
        "
hello
world
",
    ); */
}

风格版本 2021

pub fn main() {
    /*   let s = String::from(
            "
    hello
    world
    ",
        ); */
}

风格版本 2024

与原始版本无变化。

长字符串不会阻止格式化表达式

在某些情况下,长字符串以前会阻止表达式被格式化。

风格版本 2021

fn main() {
    let value = if x == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." { 0 } else {10};

    let x = Testing {
              foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_",
bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo",
};
}

风格版本 2024

fn main() {
    let value = if x
        == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
    {
        0
    } else {
        10
    };

    let x = Testing {
        foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_",
        bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo",
    };
}

修复了 impl 块中泛型的缩进

impl 项中的泛型具有过多的缩进。

风格版本 2021

impl<
        Target: FromEvent<A> + FromEvent<B>,
        A: Widget2<Ctx = C>,
        B: Widget2<Ctx = C>,
        C: for<'a> CtxFamily<'a>,
    > Widget2 for WidgetEventLifter<Target, A, B>
{
    type Ctx = C;
    type Event = Vec<Target>;
}

风格版本 2024

impl<
    Target: FromEvent<A> + FromEvent<B>,
    A: Widget2<Ctx = C>,
    B: Widget2<Ctx = C>,
    C: for<'a> CtxFamily<'a>,
> Widget2 for WidgetEventLifter<Target, A, B>
{
    type Ctx = C;
    type Event = Vec<Target>;
}

在格式化复杂的 fn 时使用正确的缩进

在某些情况下,复杂的 fn 签名可能会最终出现不寻常的缩进,现在已修复。

风格版本 2021

fn build_sorted_static_get_entry_names(
    mut entries: Vec<(u8, &'static str)>,
) -> (impl Fn(
    AlphabeticalTraversal,
    Box<dyn dirents_sink::Sink<AlphabeticalTraversal>>,
) -> BoxFuture<'static, Result<Box<dyn dirents_sink::Sealed>, Status>>
        + Send
        + Sync
        + 'static) {
}

风格版本 2024

fn build_sorted_static_get_entry_names(
    mut entries: Vec<(u8, &'static str)>,
) -> (
    impl Fn(
        AlphabeticalTraversal,
        Box<dyn dirents_sink::Sink<AlphabeticalTraversal>>,
    ) -> BoxFuture<'static, Result<Box<dyn dirents_sink::Sealed>, Status>>
    + Send
    + Sync
    + 'static
) {
}

避免嵌套元组索引表达式中出现多余的空格

嵌套元组索引表达式会错误地包含一个额外的空格。

风格版本 2021

fn main() {
    let _ = ((1,),).0 .0;
}

风格版本 2024

fn main() {
    let _ = ((1,),).0.0;
}

在带有分号的 match 块内结束 return/break/continue

match arm 中块内的 returnbreakcontinue 错误地缺少分号。

风格版本 2021

fn foo() {
    match 0 {
        0 => {
            return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        }
        _ => "",
    };
}

风格版本 2024

fn foo() {
    match 0 {
        0 => {
            return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
        }
        _ => "",
    };
}

长数组和切片模式现在被换行

长数组和切片模式以前没有被正确地换行。

风格版本 2021

fn main() {
    let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] =
        panic!();
}

风格版本 2024

fn main() {
    let [
        aaaaaaaaaaaaaaaaaaaaaaaaaa,
        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
        cccccccccccccccccccccccccc,
        ddddddddddddddddddddddddd,
    ] = panic!();
}

将最后一个表达式语句格式化为表达式

块中的最后一个语句(它是表达式)现在被格式化为表达式。

风格版本 2021

fn main() {
    let toto = || {
        if true {
            42
        } else {
            24
        }
    };

    {
        T
    }
}

风格版本 2024

fn main() {
    let toto = || {
        if true { 42 } else { 24 }
    };

    { T }
}

函数调用和宏调用之间相同的格式化

某些格式化现在在宏调用中与在函数调用中相同。

风格版本 2021

fn main() {
    macro_call!(HAYSTACK
        .par_iter()
        .find_any(|&&x| x[0] % 1000 == 999)
        .is_some());

    fn_call(
        HAYSTACK
            .par_iter()
            .find_any(|&&x| x[0] % 1000 == 999)
            .is_some(),
    );
}

风格版本 2024

fn main() {
    macro_call!(
        HAYSTACK
            .par_iter()
            .find_any(|&&x| x[0] % 1000 == 999)
            .is_some()
    );

    fn_call(
        HAYSTACK
            .par_iter()
            .find_any(|&&x| x[0] % 1000 == 999)
            .is_some(),
    );
}

为具有单个循环体的闭包强制使用块闭包

具有单个循环的闭包现在被格式化为块表达式。

风格版本 2021

fn main() {
    thread::spawn(|| loop {
        println!("iteration");
    });
}

风格版本 2024

fn main() {
    thread::spawn(|| {
        loop {
            println!("iteration");
        }
    });
}

where 子句中的空行现在被移除

where 子句中的空行现在被移除。

风格版本 2021

fn foo<T>(_: T)
where
    T: std::fmt::Debug,

    T: std::fmt::Display,
{
}

风格版本 2024

fn foo<T>(_: T)
where
    T: std::fmt::Debug,
    T: std::fmt::Display,
{
}

修复了带有属性的 let-else 语句的格式化

如果 let-else 语句具有属性,则会导致 else 子句错误地单独换行 else 部分。

风格版本 2021

fn main() {
    #[cfg(target_os = "linux")]
    let x = 42
    else {
        todo!()
    };

    // This is the same without an attribute.
    let x = 42 else { todo!() };
}

风格版本 2024

fn main() {
    #[cfg(target_os = "linux")]
    let x = 42 else { todo!() };

    // This is the same without an attribute.
    let x = 42 else { todo!() };
}

枚举变体文档注释换行的差一错误

当使用 wrap_comments 功能时,注释在列宽上被换行了差一错误。

原始

pub enum Severity {
    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still.
    Error,
    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
    Warning,
}

风格版本 2021

pub enum Severity {
    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines
    /// still.
    Error,
    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
    Warning,
}

风格版本 2024

pub enum Severity {
    /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still.
    Error,
    /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem.
    Warning,
}

format_macro_matchers 的差一错误

当使用 format_macro_matchers 功能时,matcher 在列宽上被换行了差一错误。

风格版本 2021

macro_rules! test {
    ($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{
        return;
    }};
}

风格版本 2024

macro_rules! test {
    (
        $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr
    ) => {{
        return;
    }};
}

修复了在 match => 后的注释中使用 => 时的失败

在某些情况下,如果注释在 match 表达式中的 => 之后包含 =>,则会导致格式化失败。

风格版本 2021

fn main() {
    match a {
        _ =>
        // comment with =>
                {
            println!("A")
        }
    }
}

风格版本 2024

fn main() {
    match a {
        _ =>
        // comment with =>
        {
            println!("A")
        }
    }
}

match 表达式中的多个内部属性缩进不正确

match 表达式中的多个内部属性被错误地缩进。

风格版本 2021

pub fn main() {
    match a {
        #![attr1]
    #![attr2]
        _ => None,
    }
}

风格版本 2024

pub fn main() {
    match a {
        #![attr1]
        #![attr2]
        _ => None,
    }
}

迁移

此更改可以通过使用 2024 Edition 运行 cargo fmtrustfmt 自动应用。有关迁移以及风格版本如何工作的更多信息,请参阅风格版本章节。