How to solve "cycle detected"

Hi,
I wrote this code:

use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use rand::Rng;

struct Account {
    user_name:String,
    money:Arc<(Mutex<f32>, Condvar)>
}

impl Account {
    fn change_money(&self, amount:f32) {
        let (money_lock, cond) = &*self.money;
        cond.wait_while(money_lock.lock().unwrap(), |m| {*m + amount < 0.0});
        let mut money = money_lock.lock().unwrap();
        *money += amount;
        cond.notify_all();
    }

    fn get_user_name(&self) -> String {
        self.user_name.clone()
    }

    fn get_money(&self) -> f32 {
        let (lock, _) = &*self.money;
        let money = lock.lock().unwrap();
        *money
    }

    fn new() -> Account {
        Account {
            user_name: "unknow".to_string(),
            money: Arc::new((Mutex::new(0.0f32), Condvar::new()))
        }
    }
}

struct Bank {
    accounts:Vec<Account>
}

impl Bank {

    fn create_account(&mut self, name: String, m: f32) {
        self.accounts.push(Account{
            user_name: name,
            money: Arc::new((Mutex::new(m), Condvar::new()))
        });
    }

    fn transfer_money(&self, name_a: &String, name_b: &String, amount: f32) -> bool {
        let wrap_acc_a = self.get_account_by_name(name_a);
        let wrap_acc_b = self.get_account_by_name(name_b);

        if let Some(acc_a) = wrap_acc_a {
            if let Some(acc_b) = wrap_acc_b {
                acc_a.change_money(-amount);
                acc_b.change_money(amount);
            } else {
                return false;
            }
        } else {
            return false;
        }
        true
    }

    fn total_money(&self) -> f32 {
        let mut sum:f32 = 0.0;
        for acc in self.accounts.iter() {
            sum += acc.get_money();
        }
        sum
    }

    fn random_transfer(&self, name_a: String, name_b: String) -> thread::JoinHandle<_> {
        
        thread::spawn(move || {
            let acc_a = self.get_account_by_name(&name_a);
            let acc_b = self.get_account_by_name(&name_b);
            let mut rng = rand::thread_rng();
            loop {
                let rand_money:f32 = rng.gen_range(0.0..100.0);
                self.transfer_money(&name_a, &name_b, rand_money);
                println!("Try to transfer {0}
                  From {1}({2}) to {3}({4}), Bank Total Money {5}", rand_money, name_a, acc_a.unwrap().get_money(),
                         name_b, acc_b.unwrap().get_money(), self.total_money());
            }
        })
    }

    fn get_account_by_name (&self, name:&String) -> Option<&Account> {
        self.accounts.iter().position(|x|x.get_user_name() == *name).map(|i| &self.accounts[i])
    }

    fn new() -> Bank {
        Bank {
            accounts: Vec::new()
        }
    }

}



fn main() {
    let mut bank = Bank::new();
    bank.create_account("Hahaha".to_string(), 100.0f32);
    bank.create_account("HeiHei".to_string(), 100.0f32);


}

but the compiler report

error[E0391]: cycle detected when computing function signature of `<impl at src/main.rs:41:1: 101:2>::random_transfer`
  --> src/main.rs:75:5
   |
75 |     fn random_transfer(&self, name_a: String, name_b: String) -> thread::JoinHandle<_> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: ...which requires type-checking `<impl at src/main.rs:41:1: 101:2>::random_transfer`...
  --> src/main.rs:75:5
   |
75 |     fn random_transfer(&self, name_a: String, name_b: String) -> thread::JoinHandle<_> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: ...which again requires computing function signature of `<impl at src/main.rs:41:1: 101:2>::random_transfer`, completing the cycle
note: cycle used when collecting item types in top-level module

how can I solve this?

Please post error messages in code blocks.

1 Like

You can't use incomplete types in return types. Put full type in there. thread::JoinHandle<!> or () if ! isn't supported in there yet.

1 Like

I've filed Confusing diagnostic: cycle detected when using placeholder on a function signature · Issue #82546 · rust-lang/rust · GitHub since this seems a pretty bad diagnostic

3 Likes

Ah. Thanks. It works.