Access properties of optional object/struct/variable inside parent struct

Viewed 45

I am not sure why I cannot access any field on my Vector... that Vector is an optional property (that now exists) of my dinner variable:

struct Dinner {
    name: String,
    dishes: Option<Vec<Dishes>>
}

let mut dinner = Dinner::new();
dinner.dishes = Option::from(dinner.get_dishes());

for dish in dinner.dishes {
    dish.temperature = Some("HOT");
}

println!("{:#?}", script);
error[E0609]: no field `temperature` on type `Vec<Dishes>`
  --> src/main.rs:14:21
   |
14 |                      dish.temperature = Some("HOT");
   |                           ^^^^^^^^^^^ unknown field

Update:

I just found out that when looping through the dishes

for dish in dinner.dishes {
    println!("{:#?}", dish)
}

There is only one entry, and that contains all my dishes... this is a Some(all my dishes are in here) and I need to access the content of that Some, I basically need to get rid of that Some() that wraps around the data I need to access.

1 Answers

(Note: I refer to your struct as Dish here, not Dishes, as the latter just makes this post grammatically difficult to parse)

An Option<Vec<Dish>> is not a Vec<Dish>. Even an Option<Vec<Dish>> that has a value is not a Vec<Dish>. There's no subtyping relationship here. An Option<Vec<Dish>> can be thought of as a container of zero or one dishes. In the same vein, an array of Dish is not, itself, a Dish. Even if the array happened to contain only one Dish, it would not be accurate to say that the array is, itself, a Dish.

for dish in dinner.dishes {
  ...
}

This is not iterating over a vector. This is iterating over an Option, which is a container of at most one vector. So the type of dish is Vec<Dish>, which does not have a temperature. If you know the optional value is nonempty, you can use Option::unwrap to get at the inner value

for dish in dinner.dishes.unwrap() {
  ...
}

This will panic if your assertion turns out to be wrong. But the more correct solution would be to build up the vector and then assign it to the field as a final step.

// Type annotations included for didactic purposes;
// they are not necessary in production code.
let mut dinner: Dinner = Dinner::new();
let mut dishes: Vec<Dish> = Vec::new();

for dish in dishes {
    dish.temperature = Some("HOT");
}

dinner.dishes = Some(dishes);
Related