1
votes

I am new to Rust, and have gotten some way through writing my first toy program, just a card game implementation. Here is my current file structure:

├── Cargo.lock
├── Cargo.toml
├── src
│   ├── card.rs
│   ├── deck.rs
│   ├── hand.rs
│   └── main.rs

The basic building block of course being the card struct, it looks like this:

pub struct Card {
    value: Value,
    suit: Suit,
    is_visible : bool
}

impl Card {
    pub fn new(value: &Value, suit: &Suit) -> Card {
        Card {...}
    }
}
#[derive(Clone)]
pub enum Suit {...}
#[derive(Clone)]
pub enum Value{...}

Deck implementation in deck.rs, using the card module:

#[path="card.rs"]
mod card;
pub use card::*;

pub struct Deck(Vec<Card>);

impl Deck {
    pub fn new(n_packs: u32) -> Deck {
        let mut cards = Vec::new();
        ...
        Deck(cards)
    }
    pub fn deal_from_top(&mut self, n_cards: u32) -> Vec<Card>{...}
    pub fn shuffle(&mut self) {...}

    ...
}

very similar struct, Hand is defined in module hand.rs

#[path = "card.rs"]
mod card;
pub use card::*;

pub struct Hand(Vec<Card>);

impl Hand{
    pub fn new(cards: Vec<Card>) -> Hand{
        Hand(cards)
    }
}

In main.rs, I have want to

  • create a deck,
  • shuffle it,
  • deal n cards,
  • place these cards into a Hand struct

That last one is giving me some serious grief.

Here is what I have tried:

mod hand;
mod deck;
use hand::Hand;
use deck::Deck;

fn main() { 
    let mut deck = Deck::new(1);
    deck.shuffle();
    let mut cards = deck.deal_from_top(5);
    let mut hand = Hand::new(cards);
}

Which throws a complie-time error E0308:

error[E0308]: mismatched types
  --> src/main.rs:13:30
   |
13 |     let mut hand = Hand::new(cards);
   |                              ^^^^^ expected struct `hand::card::Card`, found struct `deck::card::Card`
   |
   = note: expected struct `std::vec::Vec<hand::card::Card>`
              found struct `std::vec::Vec<deck::card::Card>`

So clearly I am missing something in my understanding of how user-defined types are 'imported' for use.

By importing the cards module, the 'Card' type used by deck, and by hand become separate types as far as main is concerned. I do not want deck or hand to reference each other to access the same namespaced version of Card.

How can I make the card struct completely reusable in this context? or is my somewhat object-oriented approach just so wide of the mark to not be achievable in idiomatic rust? Searching so far has yielded nothing, so any help is appreciated.

C.

1

1 Answers

5
votes

With #[path="card.rs"] you force your deck and hand modules to find the card submodule in a non-standard place. In deck.rs and hand.rs, writing mod card; considers card as a submodule of the two previous. In theory, these submodules should be located in src/deck/card.rs and src/hand/card.rs, hence the path= notation to find these in another place.

Instead of that, you probably want to use the card module which is at the same level. Just get rid of mod card; in those two files and write pub use super::card::*; instead of pub use::card::*;. Finally, add mod card; in main.rs so that it is discovered when main.rs is read by the compiler.

In your solution, reusing the same file for two different submodules was just a trick equivalent to copy/paste but from the language point of view, these two submodules and the struct they provide are distinct (as told by the compiler in the error message).