Slide 1

Slide 1 text

プリントデバッグを失敗させないテクニック 2024-05-14 UV Study Rust LT会 #UV_study

Slide 2

Slide 2 text

© 2024 estie Inc. • 新しい⾔語で開発し始めると気軽にプリントデバッグをしたくなるはず • プリントデバッグに必要な知識全部盛り 1

Slide 3

Slide 3 text

© 2024 estie Inc. matsu7874 SWE @ estie • ソフトウェアエンジニア • 技術広報も担当 • estieという不動産業界向けのシステムを開発する ITスタートアップ企業で働いています。 • 『実践Rustプログラミング⼊⾨』(2020) 共著 ⾃⼰紹介 2

Slide 4

Slide 4 text

© 2024 estie Inc. println! eprintln! dbg! 3

Slide 5

Slide 5 text

© 2024 estie Inc. println!は標準出⼒、eprintln!とdbg!は標準エラー fn main() { println!("Hello, stdout!"); //=> Hello, stdout! eprintln!("Hello, stderr!"); //=> Hello, stderr! dbg!("Hello, dbg!"); //=> [src/bin/01.rs:4:5] "Hello, dbg!" = "Hello, dbg!" } println! eprintln! dbg! 4

Slide 6

Slide 6 text

© 2024 estie Inc. {}で変数の中⾝も表⽰できる、が、エラーになるものもある let x = 1; println!("{}", x); //=> 1 let v = vec![1, 2, 3]; println!("{}", v); println! eprintln! dbg! 5 error[E0277]: `Vec<{integer}>` doesn't implement `std::fmt::Display` --> src/bin/02.rs:5:20 | 5 | println!("{}", v); | ^ `Vec<{integer}>` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `Vec<{integer}>` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

Slide 7

Slide 7 text

© 2024 estie Inc. {:?}でデバッグ表⽰, {:#?}でpretty-print let v = vec![1, 2, 3]; println!("{:?}", v); //=> [1, 2, 3] println!("{:#?}", v); //=> [ // 1, // 2, // 3 // ] println! eprintln! dbg! 6

Slide 8

Slide 8 text

© 2024 estie Inc. DebugとDisplay 2 7

Slide 9

Slide 9 text

© 2024 estie Inc. ⾃分で定義したstructも{:?}できないのですか︖ struct MyS { x: usize, } fn main() { let my_s = MyS { x: 12 }; println!("{:?}", my_s); } DebugとDisplay 8 error[E0277]: `MyS` doesn't implement `Debug` --> src/bin/04.rs:7:22 | 7 | println!("{:?}", my_s); | ^^^^ `MyS` cannot be formatted using `{:?}` | = help: the trait `Debug` is not implemented for `MyS` = note: add `#[derive(Debug)]` to `MyS` or manually `impl Debug for MyS` help: consider annotating `MyS` with `#[derive(Debug)]` | 1 + #[derive(Debug)] 2 | struct MyS { |

Slide 10

Slide 10 text

© 2024 estie Inc. #[derive(Debug)]アトリビュートをつけると表⽰できる #[derive(Debug)] struct MyS { x: usize, } fn main() { let my_s = MyS { x: 12 }; println!("{:?}", my_s); //=> MyS { x: 12 } } DebugとDisplay 9

Slide 11

Slide 11 text

© 2024 estie Inc. 各フィールドがDebugを実装していれば structは要素のDebugを使える #[derive(Debug)] struct MyS { x: usize, } #[derive(Debug)] struct MyWrapper { my_s: MyS, } DebugとDisplay 10 fn main() { let my_s = MyS { x: 12 }; println!("{:?}", my_s); //=> MyS { x: 12 } let my_w = MyWrapper { my_s }; println!("{:?}", my_w); //=> MyWrapper { my_s: MyS { x: 12 } } }

Slide 12

Slide 12 text

© 2024 estie Inc. ⾃由に整形したいときはtrait Displayを実装する #[derive(Debug)] struct Restaurant { name: String, location: String, rating: usize, } impl std::fmt::Display for Restaurant { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f,"{}({}): {}", self.name, self.location, "★".repeat(self.rating) ) } } DebugとDisplay 11 let r = Restaurant { name: "Diner matsu7874".to_string(), location: "Tokyo".to_string(), rating: 5, }; println!("{:?}", r); //=> Restaurant { name: "Diner matsu7874", location: "Tokyo", rating: 5 } println!("{}", r); //=> Diner matsu7874(Tokyo): ★★★★★

Slide 13

Slide 13 text

© 2024 estie Inc. dbg!や{:?}で表⽰するためにはstd::fmt::Debugが必要 {}で表⽰するためにはstd::fmt::Displayの実装が必要 DebugとDisplay 12 #[derive(Debug)] struct struct名{} impl std::fmt::Display for struct名 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f,"ここに好きな表⽰形式", /*値を表⽰する場合はここに値を書く*/) } }

Slide 14

Slide 14 text

© 2024 estie Inc. 特殊な環境でのプリントデバッグ 3 13

Slide 15

Slide 15 text

© 2024 estie Inc. 成功したテストコードの出⼒は基本的に表⽰されない test tests::test_div ... ok pub fn div(n: u32, d: u32) -> Option<(u32, u32)> { if d == 0 { return None; } let mut answer = 0; let mut n = n; while n >= d { n -= d; answer += 1; eprintln!("n={}, answer={}", n, answer); } Some((answer, n)) } 特殊な環境でのプリントデバッグ 14 #[cfg(test)] mod tests { use super::div; #[test] fn test_div() { let actual = div(10, 3); eprintln!("actual={:?}", actual); let expected = Some((3, 1)); assert_eq!(actual, expected); } }

Slide 16

Slide 16 text

© 2024 estie Inc. 失敗しているテストコードの出⼒は表⽰される pub fn div(n: u32, d: u32) -> Option<(u32, u32)> { Some((0, 0)) } #[cfg(test)] mod tests { #[test] fn test_div() { let actual = super::div(10, 3); eprintln!("actual={:?}", actual); let expected = Some((3, 1)); assert_eq!(actual, expected); } } 特殊な環境でのプリントデバッグ 15 test tests::test_div ... FAILED failures: ---- tests::test_div stdout ---- actual=Some((0, 0)) thread 'tests::test_div' panicked at src/bin/07.rs:24:9: assertion `left == right` failed left: Some((0, 0)) right: Some((3, 1))

Slide 17

Slide 17 text

© 2024 estie Inc. cargo test -- --nocapture で実⾏すると表⽰される $ cargo test -- --nocapture running 1 test n=7, answer=1 n=4, answer=2 n=1, answer=3 actual=Some((3, 1)) test tests::test_div ... ok 特殊な環境でのプリントデバッグ 16 pub fn div(n: u32, d: u32) -> Option<(u32, u32)> { if d == 0 { return None; } let mut answer = 0; let mut n = n; while n >= d { n -= d; answer += 1; eprintln!("n={}, answer={}", n, answer); } Some((answer, n)) }

Slide 18

Slide 18 text

© 2024 estie Inc. ビルドスクリプトのbuild.rsの出⼒も基本的に表⽰されない // build.rs fn main() { println!("build.rs println"); eprintln!("build.rs eprintln"); println!("cargo:rustc-env=FROM_BUILD_RS_ENV_A=TRUE"); println!("cargo:rustc-env=FROM_BUILD_RS_ENV_B=FALSE"); eprintln!("cargo:rustc-env=FROM_BUILD_RS_ENV_C=FALSE"); } 特殊な環境でのプリントデバッグ 17 [package] name = "print-debug-tutorial" version = "0.1.0" edition = "2021" build = "build.rs"

Slide 19

Slide 19 text

© 2024 estie Inc. build.rsの出⼒は –vvをつけると表⽰できる $ cargo build –vv ...省略 [print-debug-tutorial 0.1.0] build.rs eprintln [print-debug-tutorial 0.1.0] cargo:rustc-env=FROM_BUILD_RS_ENV_C=FALSE [print-debug-tutorial 0.1.0] build.rs println [print-debug-tutorial 0.1.0] cargo:rustc-env=FROM_BUILD_RS_ENV_A=TRUE [print-debug-tutorial 0.1.0] cargo:rustc-env=FROM_BUILD_RS_ENV_B=FALSE ...省略 特殊な環境でのプリントデバッグ 18

Slide 20

Slide 20 text

© 2024 estie Inc. 「やり⽅がある」って覚えておこう 必要になってから調べれば⼤丈夫です。 • println! eprintln! dbg! • DebugとDisplay • cargo test -- --nocapture • cargo build -vv まとめ 19