I am working on a ray tracer where I need to be able to change certain variables based on input on runtime. I have values such as CamDir
and CamPos
that need to be changed over runtime but keep reverting back to their default values. I think there's an issue with storing the variables back into the Renderer
struct. It would make sense, as I'm new to programming and suck at understanding borrowing and ownership stuff. Here I'll include my code on GitHub, as well as a simpler example that somewhat faithfully recreates the situation I'm dealing with. I've been struggling with this issue for quite a while, so I'd appreciate help trying to fix my terrible code.
GitHub: https://github.com/KGL8/RayTracingPaper/tree/working_snapshot
Simplified Code Example:
#[derive(Debug)]
pub struct feed {
foodId: i32,
healthy: bool
}
impl feed {
pub fn new(foodId: i32) -> feed {
feed {
foodId: foodId,
healthy: true
}
}
pub fn newValues(mut self) {
self.healthy = false;
self.foodId = 234567645;
}
}
#[derive(Debug)]
pub struct animal {
animalType: i32, // 0 = dog, 1 = cat
foodType: feed,
joy: i32 // 0% -> 100%
}
impl animal {
pub fn new(animalType: i32, foodType: feed) -> animal {
animal {
animalType: animalType,
foodType: foodType,
joy: 50
}
}
pub fn changePetFood(self) {
self.foodType.newValues();
}
}
pub fn walk(mut a: animal) {
a.changePetFood();
a.joy = 100;
}
fn main() {
let food = feed::new(264369);
let doggy = animal::new(0,food);
println!("{:?}",doggy);
walk(doggy);
println!("{:?}",doggy);
}
I've tried a whole combination of mutability, referencing, and passing as parameters, but nothing seems to work out...
Here is a tree that attempts to explain the structure I've set up for my code:
Main.rs -> [1] App.rs -> Renderer.rs -> Camera.rs -> App.rs -> Renderer.rs -> [Loop back to [1]]
You need to understand the distinction between a value and a reference.
In Rust, when you pass a value as a parameter to a function, this moves the value (except for the basic primitive types and some variations around that, which are simply copied because it costs almost nothing).
This means that now the value is not anymore in its initial location but in the parameter of the function (this is simplified, but the main idea is here): the function has consumed the value which is not available anymore in its initial location.
For example, calling walk(doggy)
consumes doggy
and you cannot display it after this call.
Instead, you should pass a reference to doggy
in order to leave it in place but interact with it anyway.
Because your intention is to mutate doggy
, you have to pass a mutable (exclusive) reference: walk(&mut doggy)
but duggy
must have been declared as mutable to allow that (let mut doggy = ...
).
Of course, the parameter of walk()
must be changed to a: &mut Animal
.
If you are OK with this till this point, then you should be able to follow the same way for the other errors (they are similar).
You just have to known that self
is a shortcut for self: Self
, &self
is a shortcut for self: &Self
and &mut self
is a shortcut for self: &mut Self
, where Self
represents the considered type for the implementation (Feed
, Animal
...)
As a side note, you should consider the compiler warnings about the naming conventions for the types, variables, functions...
And as stated in a comment, the integer animal_type
can be replaced by an enum
representing only the expected animals.
#[derive(Debug)]
pub struct Feed {
food_id: i32,
healthy: bool,
}
impl Feed {
pub fn new(food_id: i32) -> Self {
Self {
food_id,
healthy: true,
}
}
pub fn new_values(&mut self) {
self.healthy = false;
self.food_id = 234567645;
}
}
#[derive(Debug)]
pub enum AnimalType {
Dog,
Cat,
}
#[derive(Debug)]
pub struct Animal {
animal_type: AnimalType,
food_type: Feed,
joy: i32, // 0% -> 100%
}
impl Animal {
pub fn new(
animal_type: AnimalType,
food_type: Feed,
) -> Self {
Self {
animal_type,
food_type,
joy: 50,
}
}
pub fn change_pet_food(&mut self) {
self.food_type.new_values();
}
}
pub fn walk(a: &mut Animal) {
a.change_pet_food();
a.joy = 100;
}
fn main() {
let food = Feed::new(264369);
let mut doggy = Animal::new(AnimalType::Dog, food);
println!("{:?}", doggy);
walk(&mut doggy);
println!("{:?}", doggy);
}
/*
Animal { animal_type: Dog, food_type: Feed { food_id: 264369, healthy: true }, joy: 50 }
Animal { animal_type: Dog, food_type: Feed { food_id: 234567645, healthy: false }, joy: 100 }
*/