🦀

100日後にRustをちょっと知ってる人になる: [Day 69]コード整形: rustfmt

2022/11/23に公開

Day 69 のテーマ

Day 68 では、Blessed.rs で紹介されている Lint ツールの clippy の使い方を見てみました。今日も引き続き、Blessed.rs で紹介されているクレートを見てみたいかなと思います。

というわけで、開発ツールで紹介されている コードフォーマットツールの rustfmt について今日は見てみたいかなと思います。

rustfmt

以下が rustfmt のリポジトリです。見てもらえば分かるように、先日の Lint ツールの clippy 同様に、この rustfmt も rust-lang の配下におかれる Rust の公式なコードフォーマットツールです。

この rustfmt は、コードのスタイルガイドラインに従って、作成するコードを整形するために用いられるものです。
デフォルトでは、次のスタイルガイドに準拠しているようです。

インデントやライン幅、空白行、またモジュールレベルの項目やステートメント、式、型などの項目でそれぞれフォーマットを定義しています。

インストール

rustup component add rustfmt

これで、次のコマンドでコードフォーマットを実行できます。

rustfmt

あるいは

cargo fmt

コードフォーマット実行

次のような、コードスタイルがおかしなサンプルコードを作成してみます。

fn main(){
for n in 0..10{
println!("{n}: Hello, Rust!");
}
}

インデントが崩れていて、ひと目でおかしなコードだとわかりますよね。ただ、コード的には間違いはないので実行はできます。

$ cargo run

0: Hello, Rust!
1: Hello, Rust!
2: Hello, Rust!
3: Hello, Rust!
4: Hello, Rust!
5: Hello, Rust!
6: Hello, Rust!
7: Hello, Rust!
8: Hello, Rust!
9: Hello, Rust!

あと、clippy も実施してみましたが特にエラーは発生しませんでした。

ここで、cargo fmt を実行してみます。特にメッセージが表示されるわけではないのですが、実行後にソースコードを見てください。

$git diff

-fn main(){
-for n in 0..10{
-println!("{n}: Hello, Rust!");
+fn main() {
+    for n in 0..10 {
+        println!("{n}: Hello, Rust!");
+    }
 }
-}

つまり、以下のようにコードが整形されていました。

fn main() {
    for n in 0..10 {
        println!("{n}: Hello, Rust!");
    }
}

ソースコードをコミットする前には必ず rustfmt を実行するという習慣をつけておくといいかもしれないですね。

スタイルガイド設定

先にも書いていたように、rustfmt では、RFC で規定された Rust スタイルガイドに準拠したスタイルになっています。利用可能なスタイルオプションは、次のコマンドで確認出来ます。

rustfmt --help=config

スタイルガイドをカスタマイズしたい場合は、rustfmt.toml というファイルを作成して定義を行うことが可能です。

次のコマンドを実行することで、デフォルト設定を書き出してくれるので、それをベースにカスタマイズするといいと思います。

rustfmt --print-config default rustfmt.toml 

オプション一覧

option名 設定値 説明
verbose <boolean>
Default: false
Use verbose output
skip_children <boolean>
Default: false
Don't reformat out of line modules
[max_width] <unsigned integer>
Default: 100
Maximum width of each line
ideal_width <unsigned integer>
Default: 80
Ideal width of each line
[tab_spaces] <unsigned integer>
Default: 4
Number of spaces per tab
[fn_call_width] <unsigned integer>
Default: 60
Maximum width of the args of a function call before falling back to vertical formatting
[struct_lit_width] <unsigned integer>
Default: 16
Maximum width in the body of a struct lit before falling back to vertical formatting
newline_style [Windows|
Unix|
Native]
Default: Unix
Unix or Windows line endings
[fn_brace_style] [AlwaysNextLine|
PreferSameLine|
SameLineWhere]
Default: SameLineWhere
Brace style for functions
[item_brace_style] [AlwaysNextLine|
PreferSameLine|
SameLineWhere]
Default: SameLineWhere
Brace style for structs and enums
[impl_empty_single_line] <boolean>
Default: true
Put empty-body implementations on a single line
[fn_empty_single_line] <boolean>
Default: true
Put empty-body functions on a single line
[fn_single_line] <boolean>
Default: false
Put single-expression functions on a single line
[fn_return_indent] [WithArgs|
WithWhereClause]
Default: WithArgs
Location of return type in function declaration
[fn_args_paren_newline] <boolean>
Default: true
If function argument parenthesis goes on a newline
[fn_args_density] [Compressed|
Tall|
CompressedIfEmpty|
Vertical]
Default: Tall
Argument density in functions
[fn_args_layout] [Visual|
Block|
BlockAlways]
Default: Visual
Layout of function arguments
[fn_arg_indent] [Inherit|
Tabbed|
Visual]
Default: Visual
Indent on function arguments
[type_punctuation_density] [Compressed|
Wide]
Default: Wide
Determines if '+' or '=' are wrapped in spaces in the punctuation of types
[where_density] [Compressed|
Tall|
CompressedIfEmpty|
Vertical]
Default: CompressedIfEmpty
Density of a where clause
[where_indent] [Inherit|
Tabbed|
Visual]
Default: Tabbed
Indentation of a where clause
[where_layout] [Vertical|
Horizontal|
HorizontalVertical|
Mixed]
Default: Vertical
Element layout inside a where clause
[where_pred_indent] [Inherit|
Tabbed|
Visual]
Default: Visual
Indentation style of a where predicate
[where_trailing_comma] <boolean>
Default: false
Put a trailing comma on where clauses
[generics_indent] [Inherit|
Tabbed|
Visual]
Default: Visual
Indentation of generics
[struct_trailing_comma] [Always|
Never|
Vertical]
Default: Vertical
If there is a trailing comma on structs
[struct_lit_trailing_comma] [Always|
Never|
Vertical]
Default: Vertical
If there is a trailing comma on literal structs
[struct_lit_style] [Visual|
Block]
Default: Block
Style of struct definition
[struct_lit_multiline_style] [PreferSingle|
ForceMulti]
Default: PreferSingle
[enum_trailing_comma] <boolean>
Default: true
Put a trailing comma on enum declarations
report_todo [Always|
Unnumbered|
Never]
Default: Never
Report all, none or unnumbered occurrences of TODO in source file comments
report_fixme [Always|
Unnumbered|
Never]
Default: Never
Report all, none or unnumbered occurrences of FIXME in source file comments
[chain_base_indent] [Inherit|
Tabbed|
Visual]
Default: Visual
Indent on chain base
[chain_indent] [Inherit|
Tabbed|
Visual]
Default: Visual
Indentation of chain
[reorder_imports] <boolean>
Default: false
Reorder import statements alphabetically
[single_line_if_else] <boolean>
Default: false
Put else on same line as closing brace for if statements
[format_strings] <boolean>
Default: true
Format string literals where necessary
[force_format_strings] <boolean>
Default: false
Always format string literals
[chains_overflow_last] <boolean>
Default: true
Allow last call in method chain to break the line
[take_source_hints] <boolean>
Default: true
Retain some formatting characteristics from the source code
[hard_tabs] <boolean>
Default: false
Use tab characters for indentation, spaces for alignment
[wrap_comments] <boolean>
Default: false
Break comments to fit on the line
[normalise_comments] <boolean>
Default: true
Convert /* */ comments to // comments where possible
[wrap_match_arms] <boolean>
Default: true
Wrap multiline match arms in blocks
[match_block_trailing_comma] <boolean>
Default: false
Put a trailing comma after a block based match arm (non-block arms are not affected)
[match_wildcard_trailing_comma] <boolean>
Default: true
Put a trailing comma after a wildcard arm
write_mode [Replace|
Overwrite|
Display|
Diff|
Coverage|
Plain|
Checkstyle]
Default: Replace
What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage

Day 69 のまとめ

rustfmt はコードを自動に整形してくれてとても便利なツールだとわかりました。都度都度コードを整形しながらキレイな状態で保っていくとよさそうかなと思います。
また、PR するときなども礼儀として整形されたコードでコミットしたいかなと思いました。

GitHubで編集を提案

Discussion