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.
Related
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).
This question already has answers here:
How do I express mutually recursive data structures in safe Rust?
(4 answers)
Closed 1 year ago.
I have two structs that refer to each other. Once initialized, they are never mutated for the rest of the application's lifetime.
It's possible to wrap them in a Mutex or RwLock or something, but it'd be nice not to deal with those throughout the codebase, just to get things initialized.
Here's the example code (does not compile):
use std::sync::Arc;
struct First {
second: Option<Second>,
}
struct Second {
first: Option<Arc<First>>,
}
fn main() {
let first = Arc::new(First { second: None });
let mut second = Second { first: None };
second.first = Some(first.clone());
first.second = Some(second);
}
The problem:
error[E0594]: cannot assign to data in an `Arc`
--> src/main.rs:14:5
|
14 | first.second = Some(second);
| ^^^^^^^^^^^^ cannot assign
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<First>`
It's clear what's happening here; it's not possible to assign to first, because it's inside an Arc, which does not allow interior mutability.
Changing the order of operations doesn't get around the problem.
Using Arc::get_mut() won't work, because the Arc is cloned for storage in second.first.
So, is it possible to create objects with this pattern without needing runtime locking?
You have two options, depending on if you need Sync or not.
With Sync you need some synchronization structure, a RwLock should do:
use std::borrow::BorrowMut;
use std::sync::RwLock;
use std::sync::Arc;
struct First {
second: Option<Second>,
}
struct Second {
first: Option<Arc<RwLock<First>>>,
}
fn main() {
let first = Arc::new(RwLock::new(First { second: None }));
let mut second = Second { first: None };
second.first = Some(first.clone());
let mut inner = first.write().unwrap();
inner.second = Some(second);
}
Playground
If you do not need Sync, use Rc instead of Arc and RefCell:
use std::rc::Rc;
use std::cell::RefCell;
struct First {
second: Option<Second>,
}
struct Second {
first: Option<Rc<RefCell<First>>>,
}
fn main() {
let first = Rc::new(RefCell::new(First { second: None }));
let mut second = Second { first: None };
second.first = Some(first.clone());
first.borrow_mut().second = Some(second);
}
Playground
This question already has answers here:
Reducing match indentation for deeply nested properties
(2 answers)
How do I unwrap an arbitrary number of nested Option types?
(3 answers)
Are nested matches a bad practice in idiomatic Rust?
(2 answers)
How do I borrow a reference to what is inside an Option<T>?
(2 answers)
Closed 2 years ago.
How should I go about reading the value that's nested within two Options?
I have this code:
struct Person<T> {
name: &'static str,
preferences: Vec<&'static str>,
variant: Option<T>,
}
struct Driver {
seats: usize,
}
fn main() {
let list: Vec<Person<Driver>> = todo!();
let name = "some-name";
// add a bunch of Person<Driver> drivers to the `list`
let found = list.iter().find(|candidate| candidate.name == name);
// other things
}
What's the cleanest or most recommended way to access the field seats from Option<Person<Driver>> in found?
The two ways I've done it is with a nested if let or a nested match. The nested match looks a little ugly, so this is what I'm going with:
if let Some(person) = found {
if let Some(driver) = &person.variant {
println!("{:?}", driver.seats);
}
}
Is there a better way of going about it?
The reason I have an Option field called variant is since I also have Rider structs and they're literally just a Person. Since both drivers and riders have almost all the same fields, I structured it this way instead of opting to say a person: Person field in each Rider and Driver struct which felt odd.
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)
}
I have a custom struct like the following:
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
Is it possible to get the number of struct fields programmatically (like, for example, via a method call field_count()):
let my_struct = MyStruct::new(10, "second_field", 4);
let field_count = my_struct.field_count(); // Expecting to get 3
For this struct:
struct MyStruct2 {
first_field: i32,
}
... the following call should return 1:
let my_struct_2 = MyStruct2::new(7);
let field_count = my_struct2.field_count(); // Expecting to get count 1
Is there any API like field_count() or is it only possible to get that via macros?
If this is achievable with macros, how should it be implemented?
Are there any possible API like field_count() or is it only possible to get that via macros?
There is no such built-in API that would allow you to get this information at runtime. Rust does not have runtime reflection (see this question for more information). But it is indeed possible via proc-macros!
Note: proc-macros are different from "macro by example" (which is declared via macro_rules!). The latter is not as powerful as proc-macros.
If this is achievable with macros, how should it be implemented?
(This is not an introduction into proc-macros; if the topic is completely new to you, first read an introduction elsewhere.)
In the proc-macro (for example a custom derive), you would somehow need to get the struct definition as TokenStream. The de-facto solution to use a TokenStream with Rust syntax is to parse it via syn:
#[proc_macro_derive(FieldCount)]
pub fn derive_field_count(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
// ...
}
The type of input is ItemStruct. As you can see, it has the field fields of the type Fields. On that field you can call iter() to get an iterator over all fields of the struct, on which in turn you could call count():
let field_count = input.fields.iter().count();
Now you have what you want.
Maybe you want to add this field_count() method to your type. You can do that via the custom derive (by using the quote crate here):
let name = &input.ident;
let output = quote! {
impl #name {
pub fn field_count() -> usize {
#field_count
}
}
};
// Return output tokenstream
TokenStream::from(output)
Then, in your application, you can write:
#[derive(FieldCount)]
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
MyStruct::field_count(); // returns 3
It's possible when the struct itself is generated by the macros - in this case you can just count tokens passed into macros, as shown here. That's what I've come up with:
macro_rules! gen {
($name:ident {$($field:ident : $t:ty),+}) => {
struct $name { $($field: $t),+ }
impl $name {
fn field_count(&self) -> usize {
gen!(#count $($field),+)
}
}
};
(#count $t1:tt, $($t:tt),+) => { 1 + gen!(#count $($t),+) };
(#count $t:tt) => { 1 };
}
Playground (with some test cases)
The downside for this approach (one - there could be more) is that it's not trivial to add an attribute to this function - for example, to #[derive(...)] something on it. Another approach would be to write the custom derive macros, but this is something that I can't speak about for now.