課題10: 構造体の実践

マンダトリー要件

問題1: 基本的な構造体(20点)

様々な構造体を定義し、基本的なメソッドを実装しなさい。

// 座標を表す構造体
#[derive(Debug, PartialEq)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        // TODO: 実装
    }

    fn origin() -> Self {
        // TODO: 原点(0, 0)を返す
    }

    fn distance_from_origin(&self) -> f64 {
        // TODO: 原点からの距離
    }

    fn distance_to(&self, other: &Point) -> f64 {
        // TODO: 他の点との距離
    }

    fn translate(&mut self, dx: f64, dy: f64) {
        // TODO: 平行移動
    }
}

// 長方形を表す構造体
#[derive(Debug)]
struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

impl Rectangle {
    fn new(top_left: Point, bottom_right: Point) -> Self {
        // TODO: 実装
    }

    fn width(&self) -> f64 {
        // TODO: 幅を計算
    }

    fn height(&self) -> f64 {
        // TODO: 高さを計算
    }

    fn area(&self) -> f64 {
        // TODO: 面積を計算
    }

    fn contains(&self, point: &Point) -> bool {
        // TODO: 点が長方形内にあるか
    }
}

// 円を表す構造体
#[derive(Debug)]
struct Circle {
    center: Point,
    radius: f64,
}

impl Circle {
    fn new(center: Point, radius: f64) -> Self {
        // TODO: 実装
    }

    fn area(&self) -> f64 {
        // TODO: 面積を計算
    }

    fn circumference(&self) -> f64 {
        // TODO: 円周を計算
    }

    fn contains(&self, point: &Point) -> bool {
        // TODO: 点が円内にあるか
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_point() {
        let p1 = Point::new(3.0, 4.0);
        assert_eq!(p1.distance_from_origin(), 5.0);

        let p2 = Point::new(0.0, 0.0);
        assert_eq!(p1.distance_to(&p2), 5.0);

        let mut p3 = Point::new(1.0, 1.0);
        p3.translate(2.0, 3.0);
        assert_eq!(p3, Point::new(3.0, 4.0));
    }

    #[test]
    fn test_rectangle() {
        let rect = Rectangle::new(
            Point::new(0.0, 10.0),
            Point::new(10.0, 0.0),
        );
        assert_eq!(rect.width(), 10.0);
        assert_eq!(rect.height(), 10.0);
        assert_eq!(rect.area(), 100.0);
        assert!(rect.contains(&Point::new(5.0, 5.0)));
        assert!(!rect.contains(&Point::new(15.0, 5.0)));
    }

    #[test]
    fn test_circle() {
        let circle = Circle::new(Point::new(0.0, 0.0), 5.0);
        assert!((circle.area() - 78.54).abs() < 0.1);
        assert!(circle.contains(&Point::new(3.0, 4.0)));
        assert!(!circle.contains(&Point::new(10.0, 10.0)));
    }
}

提出物problem1_basic_structs.rs

問題2: ユーザー管理システム(20点)

ユーザー管理システムを実装しなさい。

use std::collections::HashMap;

#[derive(Debug, Clone)]
struct User {
    id: u64,
    username: String,
    email: String,
    age: u32,
    is_active: bool,
}

impl User {
    fn new(id: u64, username: String, email: String, age: u32) -> Self {
        // TODO: 実装(is_activeはtrue)
    }

    fn deactivate(&mut self) {
        // TODO: 実装
    }

    fn activate(&mut self) {
        // TODO: 実装
    }

    fn update_email(&mut self, new_email: String) {
        // TODO: 実装
    }
}

struct UserDatabase {
    users: HashMap<u64, User>,
    next_id: u64,
}

impl UserDatabase {
    fn new() -> Self {
        // TODO: 実装
    }

    fn add_user(&mut self, username: String, email: String, age: u32) -> u64 {
        // TODO: 実装
        // ユーザーを追加し、IDを返す
    }

    fn get_user(&self, id: u64) -> Option<&User> {
        // TODO: 実装
    }

    fn get_user_mut(&mut self, id: u64) -> Option<&mut User> {
        // TODO: 実装
    }

    fn remove_user(&mut self, id: u64) -> Option<User> {
        // TODO: 実装
    }

    fn find_by_username(&self, username: &str) -> Option<&User> {
        // TODO: 実装
    }

    fn active_users(&self) -> Vec<&User> {
        // TODO: アクティブなユーザーのリスト
    }

    fn user_count(&self) -> usize {
        // TODO: ユーザー数
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_user_database() {
        let mut db = UserDatabase::new();

        let id1 = db.add_user("alice".to_string(), "alice@example.com".to_string(), 30);
        let id2 = db.add_user("bob".to_string(), "bob@example.com".to_string(), 25);

        assert_eq!(db.user_count(), 2);

        let user = db.get_user(id1).unwrap();
        assert_eq!(user.username, "alice");

        db.get_user_mut(id1).unwrap().deactivate();
        assert_eq!(db.active_users().len(), 1);

        db.remove_user(id2);
        assert_eq!(db.user_count(), 1);
    }
}

提出物problem2_user_management.rs

問題3: 銀行口座システム(20点)

銀行口座の管理システムを実装しなさい。

#[derive(Debug)]
struct Transaction {
    amount: f64,
    description: String,
    timestamp: String, // 簡易版:文字列で時刻を保存
}

impl Transaction {
    fn new(amount: f64, description: String) -> Self {
        // TODO: 実装
        // timestampは現在時刻の文字列表現
    }
}

#[derive(Debug)]
struct BankAccount {
    account_number: String,
    owner: String,
    balance: f64,
    transactions: Vec<Transaction>,
}

impl BankAccount {
    fn new(account_number: String, owner: String) -> Self {
        // TODO: 実装
    }

    fn deposit(&mut self, amount: f64, description: String) -> Result<(), String> {
        // TODO: 実装
        // 金額チェック、残高更新、取引記録
    }

    fn withdraw(&mut self, amount: f64, description: String) -> Result<(), String> {
        // TODO: 実装
        // 金額チェック、残高チェック、残高更新、取引記録
    }

    fn balance(&self) -> f64 {
        // TODO: 実装
    }

    fn transaction_history(&self) -> &[Transaction] {
        // TODO: 実装
    }

    fn total_deposits(&self) -> f64 {
        // TODO: 全ての入金額の合計
    }

    fn total_withdrawals(&self) -> f64 {
        // TODO: 全ての出金額の合計
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_bank_account() {
        let mut account = BankAccount::new(
            "123-456".to_string(),
            "Alice".to_string(),
        );

        assert!(account.deposit(1000.0, "初期入金".to_string()).is_ok());
        assert_eq!(account.balance(), 1000.0);

        assert!(account.withdraw(300.0, "ATM出金".to_string()).is_ok());
        assert_eq!(account.balance(), 700.0);

        assert!(account.withdraw(1000.0, "残高不足".to_string()).is_err());

        assert_eq!(account.transaction_history().len(), 2);
    }
}

提出物problem3_bank_account.rs

問題4: タスク管理システム(20点)

タスク管理システムを実装しなさい。

#[derive(Debug, PartialEq, Clone, Copy)]
enum Priority {
    Low,
    Medium,
    High,
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum Status {
    Todo,
    InProgress,
    Done,
}

#[derive(Debug, Clone)]
struct Task {
    id: u32,
    title: String,
    description: String,
    priority: Priority,
    status: Status,
}

impl Task {
    fn new(id: u32, title: String, description: String, priority: Priority) -> Self {
        // TODO: 実装(statusはTodo)
    }

    fn start(&mut self) {
        // TODO: statusをInProgressに
    }

    fn complete(&mut self) {
        // TODO: statusをDoneに
    }

    fn is_done(&self) -> bool {
        // TODO: 実装
    }
}

struct TaskManager {
    tasks: Vec<Task>,
    next_id: u32,
}

impl TaskManager {
    fn new() -> Self {
        // TODO: 実装
    }

    fn add_task(&mut self, title: String, description: String, priority: Priority) -> u32 {
        // TODO: 実装
    }

    fn get_task(&self, id: u32) -> Option<&Task> {
        // TODO: 実装
    }

    fn get_task_mut(&mut self, id: u32) -> Option<&mut Task> {
        // TODO: 実装
    }

    fn remove_task(&mut self, id: u32) -> Option<Task> {
        // TODO: 実装
    }

    fn tasks_by_status(&self, status: Status) -> Vec<&Task> {
        // TODO: 実装
    }

    fn tasks_by_priority(&self, priority: Priority) -> Vec<&Task> {
        // TODO: 実装
    }

    fn high_priority_incomplete(&self) -> Vec<&Task> {
        // TODO: 高優先度で未完了のタスク
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_task_manager() {
        let mut manager = TaskManager::new();

        let id1 = manager.add_task(
            "タスク1".to_string(),
            "説明1".to_string(),
            Priority::High,
        );

        let id2 = manager.add_task(
            "タスク2".to_string(),
            "説明2".to_string(),
            Priority::Low,
        );

        manager.get_task_mut(id1).unwrap().start();
        manager.get_task_mut(id1).unwrap().complete();

        assert_eq!(manager.tasks_by_status(Status::Done).len(), 1);
        assert_eq!(manager.tasks_by_priority(Priority::High).len(), 1);
    }
}

提出物problem4_task_manager.rs

---

ボーナス課題

> ボーナス: 以下はオプションです。マンダトリー要件を完了してから挑戦してください。

ボーナス1: 図書館管理システム(5点)

図書館の本と貸出を管理するシステムを実装しなさい。

#[derive(Debug, Clone)]
struct Book {
    id: u32,
    title: String,
    author: String,
    isbn: String,
    is_available: bool,
}

struct Loan {
    book_id: u32,
    user_id: u32,
    loan_date: String,
    return_date: Option<String>,
}

struct Library {
    books: Vec<Book>,
    loans: Vec<Loan>,
    next_book_id: u32,
}

impl Library {
    fn new() -> Self {
        // TODO: 実装
    }

    fn add_book(&mut self, title: String, author: String, isbn: String) -> u32 {
        // TODO: 実装
    }

    fn borrow_book(&mut self, book_id: u32, user_id: u32) -> Result<(), String> {
        // TODO: 実装
    }

    fn return_book(&mut self, book_id: u32) -> Result<(), String> {
        // TODO: 実装
    }

    fn available_books(&self) -> Vec<&Book> {
        // TODO: 実装
    }

    fn books_on_loan(&self) -> Vec<&Book> {
        // TODO: 実装
    }
}

提出物bonus1_library/プロジェクト

ボーナス2: ショッピングカート(5点)

ECサイトのショッピングカートを実装しなさい。

#[derive(Debug, Clone)]
struct Product {
    id: u32,
    name: String,
    price: f64,
}

struct CartItem {
    product: Product,
    quantity: u32,
}

struct ShoppingCart {
    items: Vec<CartItem>,
}

impl ShoppingCart {
    fn new() -> Self {
        // TODO: 実装
    }

    fn add_item(&mut self, product: Product, quantity: u32) {
        // TODO: 同じ商品があれば数量を増やす
    }

    fn remove_item(&mut self, product_id: u32) -> Option<CartItem> {
        // TODO: 実装
    }

    fn update_quantity(&mut self, product_id: u32, quantity: u32) -> Result<(), String> {
        // TODO: 実装
    }

    fn total(&self) -> f64 {
        // TODO: 合計金額
    }

    fn item_count(&self) -> u32 {
        // TODO: 商品の総数
    }

    fn clear(&mut self) {
        // TODO: カートを空にする
    }
}

提出物bonus2_shopping_cart/プロジェクト

ボーナス3: ゲームキャラクター(5点)

RPGのキャラクターシステムを実装しなさい。

#[derive(Debug, Clone, Copy)]
enum Class {
    Warrior,
    Mage,
    Archer,
}

#[derive(Debug)]
struct Stats {
    hp: u32,
    max_hp: u32,
    mp: u32,
    max_mp: u32,
    attack: u32,
    defense: u32,
}

struct Character {
    name: String,
    class: Class,
    level: u32,
    stats: Stats,
    experience: u32,
}

impl Character {
    fn new(name: String, class: Class) -> Self {
        // TODO: クラスに応じた初期ステータス
    }

    fn take_damage(&mut self, damage: u32) {
        // TODO: ダメージを受ける
    }

    fn heal(&mut self, amount: u32) {
        // TODO: 回復
    }

    fn is_alive(&self) -> bool {
        // TODO: 実装
    }

    fn gain_experience(&mut self, exp: u32) {
        // TODO: 経験値獲得、レベルアップ処理
    }

    fn level_up(&mut self) {
        // TODO: レベルアップ
    }
}

提出物bonus3_game_character/プロジェクト

ボーナス4: 在庫管理システム(5点)

商品の在庫を管理するシステムを実装しなさい。

#[derive(Debug, Clone)]
struct Item {
    sku: String,
    name: String,
    quantity: u32,
    price: f64,
    reorder_level: u32,
}

struct Inventory {
    items: HashMap<String, Item>,
}

impl Inventory {
    fn new() -> Self {
        // TODO: 実装
    }

    fn add_item(&mut self, item: Item) {
        // TODO: 実装
    }

    fn update_quantity(&mut self, sku: &str, quantity: i32) -> Result<(), String> {
        // TODO: 在庫数を更新(正負両方対応)
    }

    fn get_item(&self, sku: &str) -> Option<&Item> {
        // TODO: 実装
    }

    fn low_stock_items(&self) -> Vec<&Item> {
        // TODO: reorder_level以下の商品
    }

    fn total_value(&self) -> f64 {
        // TODO: 在庫の総額
    }

    fn inventory_report(&self) -> String {
        // TODO: レポート生成
    }
}

提出物bonus4_inventory/プロジェクト

ボーナス5: SNS風投稿システム(5点)

SNSの投稿とコメント機能を実装しなさい。

#[derive(Debug, Clone)]
struct Comment {
    id: u32,
    user_id: u32,
    content: String,
    timestamp: String,
}

#[derive(Debug, Clone)]
struct Post {
    id: u32,
    user_id: u32,
    content: String,
    likes: u32,
    comments: Vec<Comment>,
    timestamp: String,
}

impl Post {
    fn new(id: u32, user_id: u32, content: String) -> Self {
        // TODO: 実装
    }

    fn like(&mut self) {
        // TODO: いいね数を増やす
    }

    fn add_comment(&mut self, user_id: u32, content: String) {
        // TODO: コメントを追加
    }

    fn comment_count(&self) -> usize {
        // TODO: 実装
    }
}

struct Feed {
    posts: Vec<Post>,
    next_post_id: u32,
    next_comment_id: u32,
}

impl Feed {
    fn new() -> Self {
        // TODO: 実装
    }

    fn create_post(&mut self, user_id: u32, content: String) -> u32 {
        // TODO: 実装
    }

    fn get_post(&self, id: u32) -> Option<&Post> {
        // TODO: 実装
    }

    fn get_post_mut(&mut self, id: u32) -> Option<&mut Post> {
        // TODO: 実装
    }

    fn posts_by_user(&self, user_id: u32) -> Vec<&Post> {
        // TODO: 実装
    }

    fn popular_posts(&self, min_likes: u32) -> Vec<&Post> {
        // TODO: 指定いいね数以上の投稿
    }
}

提出物bonus5_social_media/プロジェクト

---

評価基準

マンダトリー部分(80点)

項目 配点 評価ポイント
問題1:基本構造体 20点 メソッド実装の正確性
問題2:ユーザー管理 20点 データ管理の設計
問題3:銀行口座 20点 エラーハンドリング
問題4:タスク管理 20点 フィルタリングロジック

ボーナス部分(20点)

項目 配点 評価ポイント
ボーナス1:図書館 5点 貸出管理
ボーナス2:カート 5点 商品管理
ボーナス3:キャラクター 5点 ステータス管理
ボーナス4:在庫 5点 レポート機能
ボーナス5:SNS 5点 コメント機能

: ボーナスは最大20点まで加算されます。

---

提出方法

ファイル構成

rust-foundations-10/
├── problem1_basic_structs.rs
├── problem2_user_management.rs
├── problem3_bank_account.rs
├── problem4_task_manager.rs
└── bonus/
    ├── bonus1_library/
    ├── bonus2_shopping_cart/
    ├── bonus3_game_character/
    ├── bonus4_inventory/
    └── bonus5_social_media/

提出期限

  • マンダトリー:第10章学習後、1週間以内
  • ボーナス:コース修了時まで

---

ヒント

問題1のヒント

distance_to実装:

fn distance_to(&self, other: &Point) -> f64 {
    let dx = self.x - other.x;
    let dy = self.y - other.y;
    (dx * dx + dy * dy).sqrt()
}

問題2のヒント

find_by_username実装:

fn find_by_username(&self, username: &str) -> Option<&User> {
    self.users.values().find(|u| u.username == username)
}

問題3のヒント

deposit実装:

fn deposit(&mut self, amount: f64, description: String) -> Result<(), String> {
    if amount <= 0.0 {
        return Err("金額は正の数である必要があります".to_string());
    }
    self.balance += amount;
    self.transactions.push(Transaction::new(amount, description));
    Ok(())
}

---

学習の確認

この課題を通じて、以下を理解できたか確認してください:

  • [ ] 構造体の定義と初期化
  • [ ] メソッドの実装(&self、&mut self、self)
  • [ ] 関連関数(new、コンストラクタ)
  • [ ] implブロックの使い方
  • [ ] タプル構造体とnewtype パターン
  • [ ] Debugトレイトの自動導出
  • [ ] 構造体を使ったデータ管理

おめでとうございます!Rust Foundations コースの基礎編を完了しました。次のステップとして、より高度なトピックに進みましょう。