質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

2980閲覧

【Rust】Print!()とread_line()の実行が前後することへの疑問

noid

総合スコア3

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2021/11/12 15:50

編集2021/11/12 16:08

前提・実現したいこと

最近Rustを勉強し始めた者です。
こちらのサイトで見よう見まねしていたところ、以下のような記述を見かけました。
https://doc.rust-jp.rs/book-ja/ch02-00-guessing-game-tutorial.html

println!("Please input."); let mut input=String::new(); io::stdin() .read_line(&mut input) .expect("Error: failed to read line.\n");

こうしたとき、実行は以下のようになると思います。

Please input. <入力>

これ自体には何の問題もないと思います。
ただ少し自分なりにアレンジを加えてみたくなり、コードを以下のように変更しました。

print!("input: "); let mut input=String::new(); io::stdin() .read_line(&mut input) .expect("Error: failed to read line.\n");

ここで予想外の問題が発生しました。
Print!()は確かにread_line()の前にあるので、アルゴリズムは「出力→入力」のようになると予想していましたが、実行は以下のようなりました。

<入力> input:

これはRustの仕様なのか、それとも自分の環境のせいなのかは自分では判断できないので、どなたかご教授頂けるとありがたいです。

該当のソースコード

rust

1use std::io; 2 3fn main(){ 4 print!("input: "); 5 let mut input=String::new(); 6 io::stdin() 7 .read_line(&mut input) 8 .expect("Error: failed to read line.\n"); 9 10 print!("your input is {}\n",input); 11}

試したこと

自分なりに調べてみたところ、こちらのサイトに辿り着きました。
https://www.webdevqa.jp.net/ja/rust/rustで末尾の改行なしで出力を印刷するにはどうすればよいですか?/826307055/

しかし_print!()_等調べてもよく分からないマクロがあり、結局疑問の解消には至りませんでした。

補足情報

開発環境
Visual Studio Code ver. 1.61

実行環境
CPU:Intel Core i5 1.10 - 1.50[GHz]
OS:Windows 10 Home ver. 21H1
メモリ:8.00[GB]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

これは、Rust に限らず起こりうる現象です。
標準出力へ文字を出力する動作は、究極的にはあるメモリ領域へデータを書き込むことです。
しかし、書き込みのときに1文字ずつ書き込んでいると、時間がかかります。
そこで、標準出力への出力命令があると、標準出力にデータが転送される前に、中間領域(バッファ)にコピーされます。(これを「バッファされる」といいます。)
そして、中間領域に一定以上の文字が溜まったり、特定のきっかけがあったりすると、文字がコンソールに出力(本当の書き込み用の領域にデータが転送)されます。
その「きっかけ」の1つが、「改行文字の送出」です。

今回出てくるマクロのうち、 println! は「指定した内容と改行文字を標準出力に書き込む」マクロ、 print! は「指定した内容だけを改行文字に書き込む」マクロです。
アレンジされたソースコードは、アレンジ前と比べ、 "input: " の後に改行文字が含まれていません。
したがって、プログラムは(おそらくまだバッファ領域に十分な空きがあることから)すぐには標準出力に書き込みをしなくていいと判断し、データを中間領域に留め置きます。
ユーザーが入力をすると初めて、最後の print! 命令に含まれる \n によって改行文字が送出され、今までバッファされていた文字が出力されます。よって、コンソール上は入力と出力が逆に見えるわけです。

解決方法は、中間領域にある文字を強制的に標準出力に書き出させることです。
これを「フラッシュ(flush)する」と言います。
Rust では、use std::io::{stdout, Write}; とインポートした状態で stdout().flush().unwrap(); を実行すると、これが実現できるようです。

ここまで書いて、ほぼ同じ症状について説明した Qiita 記事を見つけました。こちらになります
flush の使い方も掲載されていますので、合わせてご参照ください。

投稿2021/11/12 19:01

THidrica

総合スコア22

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

noid

2021/11/13 03:09

丁寧なご回答ありがとうございます! 提案して下さった方法を実装したところ、無事解決しました! なるほど...Cではprintf()等で即時標準出力されていたので、少し違和感がありますね。 ですが何度も連続して出力したい時は、THidricaさんのご説明の通りprintln!()の方が効率が良さそうです。 ありがとうございました!
thkana

2021/11/13 04:49

> Cではprintf()等で即時標準出力されていた Cにそんな決まりはありません。あなたの使っていたCの処理系がそうだった、というだけのことでしょう。 MicrosoftC(VisualStudio)はバッファリングしないようですが、gccはデフォルトではバッファリングしますので、Cでも同様の質問は散見されます。'C printf バッファ' 等でググってみるといくつもヒットするでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問