Screen構造体
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 52/61。
チャレンジ
簡単いよいよ、すべてのUIコンポーネントを一つにまとめる時が来ました!トレイトオブジェクトを使用して、さまざまな描画可能なコンポーネントのコレクションを保持できる Screen 構造体を作成します。ここで Vec<Box<dyn Draw>> の真価が発揮されます。一つのコレクションで複数のコンポーネントタイプを管理できるのです。
成長を続けるプロジェクトに新しいモジュールを追加します:
draw.rs: 以前のチャレンジで作成したDrawトレイト。text_field.rs:Text: {content}と出力するTextFieldコンポーネント。button.rs:Button: {label} (width: {width})と出力するButtonコンポーネント。screen.rs:Vec<Box<dyn Draw>>型のパブリックフィールドcomponentsを持つScreen構造体を作成します。空のスクリーンを作成するnew関連関数と、Box<dyn Draw>を受け取ってコンポーネントのベクタに追加するaddメソッドを実装してください。main.rs: すべてのモジュールを統合します。Screenを作成し、そこにTextFieldとButtonを追加して、スクリーンのコンポーネントを反復処理し、それぞれに対してdraw()を呼び出します。
Screen はトレイトオブジェクトを格納する必要があるため、Draw トレイトに対して dyn キーワードを使用します。add メソッドはコンポーネントのベクタを変更するため、&mut self を受け取る必要があります。
以下の入力が提供されます:
- 1行目: テキストフィールドのコンテンツ (content)
- 2行目: ボタンのラベル (label)
- 3行目: ボタンの幅 (width)(数値として)
出力は、追加された順に各コンポーネントをそれぞれの行に表示する必要があります:
Text: Hello
Button: Click Me (width: 80)自分で試してみよう
mod draw;
mod text_field;
mod button;
mod screen;
use draw::Draw;
use text_field::TextField;
use button::Button;
use screen::Screen;
pub struct Label {
pub text: String,
}
impl Draw for Label {
fn draw(&self) {
println!("{}", self.text);
}
}
fn main() {
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let content = input1.trim().to_string();
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let label = input2.trim().to_string();
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let width: u32 = input3.trim().parse().expect("Failed to parse width");
// TODO: Screen::new() を使用して Screen を作成する
// TODO: Box::new() でラップした TextField を screen に追加する
// TODO: Box::new() でラップした Button を screen に追加する
// TODO: screen.components を反復処理し、各コンポーネントの draw() を呼び出す
}