Rustで一行が100文字以上になるとフォーマットできなくなる

100字以上の文字列を扱う場合、その行orファイル全体がフォーマットができなくなる時がある。

また、vscodeやIDEAでは書いてる時に怒られないし、ビルドしてもエラーになるわけではないので全然気付けなかった…

※この記事は明確な根拠はなく推測である部分があります。

結論

直接的な原因は見つけられなかった…

推測だが、rustのガイドラインでは一行の文字数を99文字以下にするように推奨しているらしいので、100文字以上にすると想定外な挙動になってしまうこともあるのかもしれない。99文字以下を心がけよう!

環境

❯ cargo -V
cargo 1.59.0 (49d8809dc 2022-02-10)

❯ rustc --version            
rustc 1.59.0 (9d1b2106e 2022-02-23)

❯ rustup component list | grep "(installed)"
cargo-aarch64-apple-darwin (installed)
clippy-aarch64-apple-darwin (installed)
rls-aarch64-apple-darwin (installed)
rust-analysis-aarch64-apple-darwin (installed)
rust-src (installed)
rust-std-aarch64-apple-darwin (installed)
rustc-aarch64-apple-darwin (installed)
rustfmt-aarch64-apple-darwin (installed)

確認してみたこと

以下のように引数内の行ではインデント含め100文字未満で記述する必要があるようだ。ただし、コメントやカンマや丸括弧はカウントされてなさそう…

// これより長い文字列を引数内で扱うと、この行だけorファイル全体がフォーマットができなくなる
assert_eq!(
    "678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", // 99文字(インデントとダブルクォーテーション含める, `,`を除く)
    "678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678" // 99文字
);

// インデントが増えても同様
fn main() {
    assert_eq!(
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", // 99文字(インデントとダブルクォーテーション含める, `,`を除く)
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678" // 99文字
    );
    let s =
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678";
}

fn hellooooo12345678901234567890123456789012345678901234567890123456789012345678901234567890123456(
) -> i32 {
    5
}
// これより長い関数名を引数内で扱うとファイル全体でフォーマットができなくなる
assert_eq!(
    5,
    helloooooo1234567890123456789012345678901234567890123456789012345678901234567890123456789012345( // `(`を除いて99文字
    )
);

また、以下のように100行越えを一行で書く分には、ファイル全体がフォーマットできなくなるわけではないが、

assert_eq!("test", "6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
let s = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"

以下のように謎に空白を作ってしまっても、この行だけはフォーマットできない

assert_eq!(    "test"    , "6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
let      s        =                              "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";

調べたこと

残念ながら直接的な原因は見つけられなかった…。

推測だがrustのガイドラインでは一行の文字数を99文字以下にするように推奨しているらしいので、100文字以上にすると想定外な挙動になってしまうこともあるのだろうか…

ちなみに100文字ではなく99文字というのは、pep8の79文字推奨と同様の理由らしい。以下参考

以下、pep8の引用

ほとんどのツールのデフォルトの折り返し動作は、コードの見た目の構造を壊し、理解するのを難しくします。79文字という制限は、ウィンドウの幅を80に制限し、行を折り返すときにツールが行末にマーカーを置いたとしても、エディタに折り返す動作をさせない目的で選ばれています。

引用: はじめに — pep8-ja 1.0 ドキュメント (参照: 2022/4/6)

また、rustのガイドラインについて、こちらのPRまでは「一行は80文字以下にすべきで、100文字以下は必須」ということだった。というのもあり、100文字に対する折り返しを考慮すると99文字ということらしい。

rustのガイドラインのPR: Decrease line lengths by one by chris-morgan · Pull Request #12 · rust-lang/rust-guidelines