Coming from PHP and freshly entering the realm of Rust, I'm trying to 'port' my legacy PHP code to Rust. Although I've spent many weeks trying to dive into the docs and try to write the code in Rust, it simply won't compile.
I've tried all options I could find on SO, including the Rc<RefCell<x>> construct. Obviously the PHP code has a bad design, but I can't see how to improve it. Any pointers in the right direction will be greatly appreciated!
PHP:
class Database {
function build_row() : Row {
return new Row($this);
}
}
class Row { // with AR properties
protected $db;
function __construct(Database $db) {
$this->db = $db;
}
}
$db = new Database;
$row = $db->build_row();
All of my attempts have failed because of the borrow checker:
pub struct Database {}
impl Database {
pub fn new() -> Self { Database {} }
pub fn build_row(&mut self) -> Row {
Row::new(&mut self)
}
}
pub struct Row<'a> {
db: &'a mut Database,
}
impl<'a> Row<'a> {
pub fn new(db: &'a mut Database) -> Self {
Row { db }
}
}
fn main() {
let db = Database::new();
let _row = db.build_row();
}
EDIT:
The problem can be solved by changing the thinking pattern.
PHP is OOP, with objects containing data and methods. Each object IS A thing. So that each Active Record object can own a mutable reference to the database connection object to perform operations on data in the database.
Rust's borrow checker does not allow this. Rust is behaviour oriented. There can be only one mutable reference at a time (in the same scope). Because of this, a different control flow is implicitly enforced. This is actually a good thing, although it requires a different mind set.
When modelling OOP classes to Rust structs, the structs and their implementations ACT AS A thing. This means that the Active Record structs can not own their own mutable reference to the database connection struct. Instead they have functions (like load(..) and save(..)) to which the mutable reference is passed, for whenever the AR struct needs to work with the database.
So the roort cause of the problem is that this difference between OOP and Rust is mostly presumed and not too explicitly spelled out. Which makes it harder to notice for developers like me, who are new to Rust and have spent too many years with OOP.