Recursive function call?

I'm following a rust course and I've a hit some confusion with a function in the code that looks to me to be a recursive function, but the instructor hasn't said anything about it being recursive. And recursive or not, I'm not understanding how the function works. My confusion is with the 2nd line in the function where it seems to be calling itself, but I don't see return or implicit return anywhere in sight, and again, the instructor isn't covering recursive functions at all at this point as far as I can tell.

Here's the function:

    fn shuffle(&mut self) {
        let mut rng = thread_rng();
        self.cards.shuffle(&mut rng);
    }

And here's the whole program:

use rand:: { thread_rng, seq::SliceRandom };

#[derive(Debug)]
struct Deck {
    cards: Vec<String>,
}

impl Deck {
    fn new() -> Self {
        let suits = ["Hearts", "Spades", "Diamonds"];
        let values = ["Ace", "Two", "Three"];
        
        let mut cards = vec![];
        
        for suit in suits {
            for value in values {
                let card = format!("{} of {}", value, suit);
                cards.push(card);
            }
        }
    
        Deck { cards }
    }
    
    fn shuffle(&mut self) {
        let mut rng = thread_rng();
        self.cards.shuffle(&mut rng);
    }
}

fn main() {
    let mut deck = Deck::new();
    
    deck.shuffle();
    
    println!("Here's your deck: {:#?}", deck);
}

This is calling a different shuffle method; the one defined by the cards field. In this case, it’s provided by the SliceRandom trait which you’re useing in the top line of the program.

Neither of these methods return anything of interest; they instead modify the held items through the &mut self reference.

1 Like

Thanks, but still confused.
self.cards.shuffle(&mut rng);

self is the deck itsefl,
.cards is a property of the deck,
shuffle is a function of the deck.

If that shuffle within the shuffle function were part of SliceRandom, I would think we would have to be calling it with rng, rng.shuffle ?

SliceRandom is a trait, which means that it adds new methods to whatever type it’s implemented for. In particular, SliceRandom is implemented for slices [T], giving them a shuffle method.

self.cards is a Vec, but can act like a slice in some situations (like this one) due to its Deref and DerefMut implementations.

1 Like

Thanks again. I wish the instructor had explained that a bit, not sure how anyone taking that course would know that these are two different shuffle functions. I wish the one implemented with SliceRandom would have been written more like one of these:

SliceRandom::shuffle,
rand::shuffle, or
thread_rng:shuffle

something to let me know it's not the same shuffle.

Anyway, thanks again, I appreciate the clairification.

The way the instructor wrote it is what you’ll see in most Rust programs, but you can be more explicit. This is equivalent, for example:

SliceRandom::shuffle(&mut *self.cards, &mut rng);

If you want to be even more explicit about it:

SliceRandom::shuffle(self.cards.as_mut_slice(), &mut rng);

Or even:

<[String] as SliceRandom>::shuffle(self.cards.as_mut_slice(), &mut rng);
2 Likes

Tiny nit, this needs to be a reborrow &mut *self.cards for this call to work, because deref coercion happens as part of method call resolution which is not applied with fully qualified syntax or the Trait::method shorthand.

2 Likes

Thanks; fixed.

1 Like