This question already has answers here:
How can I port C++ code that uses the ternary operator to Rust?
(3 answers)
How do I idiomatically convert a bool to an Option or Result in Rust?
(4 answers)
Closed 1 year ago.
In C, there is the conditional operator on the form int x = foo > bar ? 1 : 0;. According to this issue, that seems to be something the Rust developers do not want to implement. If one wants to be concise: Is there a Rust equivalent/shorthand version to do the same?
struct Config {
timeout: Option<u32>,
}
impl Config {
// C-style conditional operator
pub fn new(timeout: u32) {
Config {
timeout == 0 ? None : Some(timeout)
}
}
// My attempted Rust approach
pub fn new(timeout: u32) {
let mut t = None;
if timeout != 0 {
t = Some(timeout);
}
Config { timeout: t }
}
}
fn main() {
let config = Config::new(0);
}
I guess I have two problems with the Rust approach as of now: 1) I need to create a new variable which is very hard to name anything meaningful and 2) the code is less concise than the C-style conditional operator (though perhaps more explicit).
Related
This question already has answers here:
How to filter a vector of custom structs?
(1 answer)
How do I conditionally check if an enum is one variant or another?
(2 answers)
Closed 2 years ago.
I can filter the active classes as follows, but how can I achieve bringing all the classes where their status is not Online? Status for not active can be Cancelled, Deferred, or Optional.
pub enum Status {
Online,
Cancelled,
Deferred,
Optional,
}
pub struct CustomFilter {
pub status: Option<Status>,
}
fn example() {
let mut custom_filter = CustomFilter::default();
custom_filter.status = Some(Status::Online);
let online_classes = self.get_classes_with_filter(custom_filter).await?;
// where Status -> Cancelled, Deferred, Optional
let non_active_classes = todo!("??");
}
How about something along the lines of:
let foo: Vec<_> = whatever;
let active_classes: Vec<_> = foo.iter().filter(|x| x.status == Status::Active).collect();
let non_active_classes: Vec<_> = foo.iter().filter(|x| x.status != Status::Active).collect();
Not sure if this is what you intended.
If your question is "Can I store !Active or Cancelled | Deferred | Optional in an Status?" then the answer is no. Maybe if your enum worked like bitflags but that doesn't appear to be the case here.
You'd have to store them individually in a Vec or something more complicated like:
enum StatusFilter {
Include(Vec<Status>),
Exclude(Vec<Status>),
}
pub struct CustomFilter {
pub status: StatusFilter,
}
custom_filter.status = StatusFilter::Exclude(vec![Status::Active]);
I'd recommend not doing this and use functor-based filtering like #Luke has suggested if at all possible. Its much more straightforward, more flexible to use and implement, and it follows conventions in the standard library.
This question already has answers here:
How do you access enum values in Rust?
(6 answers)
Closed 2 years ago.
Here is code snippet, illustrating the problem:
pub enum Foo1 {
Bar(Foo2)
}
pub enum Foo2 {
Inner(Foo3)
}
pub struct Foo3 {
pub val: i32
}
fn main() {
let s2 = Foo1::Bar(Foo2::Inner(Foo3 { val: 5 }));
// println!("{}", s2.); // I want to print val field of Foo3 struct
}
How to do it without pattern matching?
Normally, I would reach for if let when you're only interested in one match branch:
if let Foo1::Bar(Foo2::Inner(foo3)) = s2 {
println!("{}", foo3.val);
}
Your case is unusual in that none of your enums have more than one element – the if would always be true, which would raise an "irrefutable_let_patterns" warning.
Rather than silencing this warning (for the particular statement), a direct let binding is enough:
let Foo1::Bar(Foo2::Inner(foo3)) = s2;
println!("{}", foo3.val);
Thanks, Sebastian Redl, for this tip!
I found what was looking for. Field destruction is what I needed.
if let Foo1::Bar(Foo2::Inner(Foo3{val:x})) = s2 {
println!("{}", x)
}
This question already has answers here:
What's the difference between placing "mut" before a variable name and after the ":"?
(4 answers)
Why does Rust allow mutation through a reference field using an immutable binding?
(1 answer)
Closed 2 years ago.
After a lot of struggle getting used to borrowing, references, ownership etc. and trying to follow the compiler's suggestions how to fix certain issues, I ended up with the following pair of functions in my first bit of Rust code.
fn adjust_culture(mut cooperating_families: Vec<&mut Family>) {
for f in cooperating_families.iter_mut() {
mutate_culture(f);
}
let family: Option<&&mut Family> = cooperating_families.choose(&mut rand::thread_rng());
match family {
None => {},
Some(f) => {
let target: Culture = f.culture;
for f2 in cooperating_families {
f2.culture = target;
}
}
}
}
fn mutate_culture(family: &mut Family) {
if family.seasons_till_next_mutation > 0 {
family.seasons_till_next_mutation -= 1;
}
if family.seasons_till_next_mutation == 0 {
let i: u8 = rand::thread_rng().gen_range(0, culture_dimensionality);
family.culture ^= 1 << i;
}
}
The second one makes sense to me, and preventing it from gaining additional borrowing decoration was a major point getting me to this solution. But adjust_culture confuses me: Why did the compiler suggest to add the mut before cooperating_families in the function's parameter definition?
I thought I would just have to pass a mutable binding to access the fields of the individual families, but with another function
fn extract_resources(patch: Patch, group: Vec<&mut Family>, total_labor_here: usize) -> KCal {
let labor: u8 = group.iter().map(|f| {f.effective_size as u8}).sum();
let resources_extracted = resources_from_patch(
patch, labor as usize, total_labor_here - labor as usize,
false);
for family in group {
family.stored_resources +=
resources_extracted * family.effective_size as f32 / labor as f32
}
return resources_extracted
}
Rust told me that group does not need to be mutable, and now I'm quite confused.
Which bit of adjust_culture has a chance to change the value of cooperating_families instead of just the objects inside it? How do I avoid that from happening – my mental idea of the semantics says is should not happen?
This question already has answers here:
Cannot move out of value which is behind a shared reference when unwrapping
(2 answers)
How to borrow an unwrapped Option<T>? [duplicate]
(1 answer)
Closed 3 years ago.
I would like to write a method on a struct which borrows a value wrapped in an Option in one of its properties/fields.
Is it doable ?
Consider
struct A {}
struct Obj {
a: Option<A>
}
impl Obj {
fn ref_to_a(&self) -> &A {
//&self.a.unwrap() <-- How do I implement this ?
}
}
Playground
You can use Option::as_ref to "Convert from Option<T> to Option<&T>."
impl Obj {
fn ref_to_a(&self) -> &A {
self.a.as_ref().unwrap()
}
}
Of course you shouldn't use unwrap, but at least expect.
I don't know why you are not borrowing Option itself, but you can mimic unwrap behavior by this way :
impl Obj {
fn ref_to_a(&self) -> &A {
match self.a {
Some(ref a) => return a,
None => panic!("There is no value"),
}
}
}
Note :
Should I avoid unwrap in production application?
This question already has an answer here:
Why does removing return give me an error: expected type `()` but found type
(1 answer)
Closed 6 years ago.
I have a world object:
use rand::{thread_rng, Rng};
use super::world::World;
pub struct Worlds {
worlds: Vec<World>
}
impl Worlds {
pub fn new(world: Vec<World>) -> Worlds {
Worlds { worlds: world }
}
pub fn get_random_world(&self) -> World {
let mut rng = thread_rng();
if self.worlds.len() > 0 {
let world_index: usize = rng.gen_range(0, self.worlds.len());
self.worlds[world_index]
}
self.worlds[0]
}
}
The structure Worlds takes a vector of structures called World (I can post that code if you need it).
get_random_world is supposed to return a World structure, and does with self.worlds[world_index], but apparently it expects a ().
I'm lost; I told it what to return, it returns that but it expects something different?
|
20 | self.worlds[world_index]
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `game::world::world::World`
|
= note: expected type `()`
= note: found type `game::world::world::World`
I'm not sure what to do at this point.
Your if block doesn't return anything.. flow will fall through here:
if self.worlds.len() > 0 {
let world_index: usize = rng.gen_range(0, self.worlds.len());
self.worlds[world_index]
} // <--- ... this drops down
self.worlds[0]
Here is a simple reproduction of your issue: Playground link
There are two ways you can fix this. First, you can explicitly return in the conditional (View it on the playground):
if self.worlds.len() > 0 {
let world_index: usize = rng.gen_range(0, self.worlds.len());
return self.worlds[world_index]; // Explicitly return out of here
}
self.worlds[0]
The more "idiomatic" approach I guess would be to add an else block, so that the value the conditional evaluates to is actually what the function returns (View it on the playground):
if self.worlds.len() > 0 {
let world_index: usize = rng.gen_range(0, self.worlds.len());
self.worlds[world_index]
} else {
self.worlds[0]
}
Now, no matter what logical branch the code takes, the expression that results will be returned from the function.