Rust 를 잘 쓰는 법 1 — clippy 와 rustfmt 로 습관을 잡는다
clippy 는 컴파일은 되지만 Rust 답지 않거나 실수하기 쉬운 코드를 짚어 주는 린터이고, rustfmt 는 코드 모양을 한 가지로 맞추는 포매터다. 둘 다 rustup 으로 Rust 를 깔 때 함께 깔린다. 다른 언어 습관으로 쓴 함수 하나에서 clippy 경고 다섯 개를 받고, help 대로 고쳐 깨끗하게 만든다.
01 다른 언어 습관으로 쓴 함수
점수 평균을 구하는 함수다. 컴파일도 되고 답도 맞다.
fn average(scores: &Vec<i32>) -> f64 {
if scores.len() == 0 {
return 0.0;
}
let mut total = 0;
for i in 0..scores.len() {
total = total + scores[i];
}
return total as f64 / scores.len() as f64;
}
fn main() {
let scores = vec![72, 85, 90];
let copy = scores.clone();
println!("{}", average(©));
}cargo clippywarning: unneeded `return` statement
--> src/main.rs:9:5
|
9 | return total as f64 / scores.len() as f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#needless_return
= note: `#[warn(clippy::needless_return)]` on by default
help: remove `return`
|
9 - return total as f64 / scores.len() as f64;
9 + total as f64 / scores.len() as f64
|
warning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
--> src/main.rs:1:20
|
1 | fn average(scores: &Vec<i32>) -> f64 {
| ^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#ptr_arg
= note: `#[warn(clippy::ptr_arg)]` on by default
help: change this to
|
1 - fn average(scores: &Vec<i32>) -> f64 {
1 + fn average(scores: &[i32]) -> f64 {
|경고 다섯 개 가운데 앞의 둘이다. 읽는 법은 컴파일 오류와 같다(입문 2편의 무엇·어디·고치는 법).
- needless_return — 함수 끝의
return은 필요 없다. 마지막 식이 반환값이다(입문 11편).help가-·+로 고친 줄을 보여 준다. - ptr_arg —
&Vec<i32>보다&[i32](슬라이스, 입문 21편)를 받으라는 것이다. 슬라이스로 받으면Vec도 배열도 넘길 수 있다.
나머지 셋은 이렇다.
warning: length comparison to zero
--> src/main.rs:2:8
|
2 | if scores.len() == 0 {
| ^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `scores.is_empty()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#len_zero
= note: `#[warn(clippy::len_zero)]` on by default- len_zero —
len() == 0대신is_empty(). - needless_range_loop — 번호로 도는
for i in 0..len()대신 반복자(입문 14·37편). - assign_op_pattern —
total = total + x대신total += x.
#[warn(clippy::…)] 의 이름으로 문서를 찾으면 왜 그런지 설명과 예가 있다. 경고마다 help 의 링크가 그 문서다.
warning: `report` (bin "report") generated 5 warnings (run `cargo clippy --fix --bin "report" -p report -- ` to apply 3 suggestions)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s마지막 줄이 "5개 가운데 3개는 cargo clippy --fix 로 자동으로 고칠 수 있다" 고 알려 준다. 자동 고침은 편하지만, 처음에는 손으로 고치며 이유를 익히는 편이 낫다.
02 help 대로 고친 판
fn average(scores: &[i32]) -> f64 {
if scores.is_empty() {
return 0.0;
}
let total: i32 = scores.iter().sum();
total as f64 / scores.len() as f64
}
fn main() {
let scores = vec![72, 85, 90];
println!("{}", average(&scores));
} Checking report v0.1.0 (~/projects/report)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.41s경고 없이 Finished 만 나왔다. 줄 수도 줄고 뜻도 더 잘 보인다. 1편에서 본 대로 반복자 판이 느리지도 않다.
03 rustfmt — 모양은 기계에 맡긴다
띄어쓰기·줄바꿈이 제멋대로인 파일에 cargo fmt --check 를 돌렸다. --check 는 고치지 않고 차이만 보여 준다.
cargo fmt --check -- --color neverDiff in ~/projects/report/src/main.rs:1:
-fn average(scores:&[i32])->f64{
- if scores.is_empty() { return 0.0; }
- let total:i32=scores.iter().sum();
- total as f64/scores.len() as f64
+fn average(scores: &[i32]) -> f64 {
+ if scores.is_empty() {
+ return 0.0;
+ }
+ let total: i32 = scores.iter().sum();
+ total as f64 / scores.len() as f64
}
fn main() {
Diff in ~/projects/report/src/main.rs:8:
- let scores = vec![72,85,90];
+ let scores = vec![72, 85, 90];
println!("{}", average(&scores));
}
-- --color never 는 글에 싣느라 색을 끈 것이고, 터미널에서는 빨강·초록으로 보인다. - 줄이 지금 모양, + 줄이 rustfmt 의 모양이다. 차이가 있으면 종료 코드 1 로 끝난다. --check 없이 cargo fmt 를 치면 파일을 그 모양으로 바로 고친다.
모양을 두고 사람끼리 따질 일이 없어지고, 코드 리뷰의 차이(diff)에 모양 변경이 섞이지 않는다. 그래서 Rust 프로젝트는 거의 모두 rustfmt 의 기본 모양을 그대로 쓴다.
04 실습 — 저장소에 넣는 두 줄
CI(자동 검사)나 커밋 전에 이 두 줄을 돌리게 한다.
cargo fmt --check
cargo clippy --all-targets -- -D warnings--all-targets 는 테스트 코드까지, -D warnings 는 경고를 오류로 바꿔 하나라도 있으면 실패하게 한다. 11편에서 AI 에이전트에게 일을 맡길 때도 이 두 줄이 그대로 "다 됐는지" 를 판정하는 기준이 된다. 자기 프로젝트에 cargo clippy 를 한 번 돌려 몇 개가 나오는지 세어 보자. 다음 편은 clippy 가 다 잡지 못하는 설계 습관이다.