I want to make an enum from a struct.
The definitions:
struct Point {
x: u8,
y: u8,
}
enum Message {
Move { x: u8, y: u8 },
nothing,
}
So if I have instantiated a Point in my code, how can I make a Message from the struct?
I've tried this code:
Message::Move(Point { x: 10, y: 15 })
But this code throws an error saying
error[E0423]: expected function, tuple struct or tuple variant, found struct variant `Message::Move`
Your enum variant can simply contain an instance of the struct.
enum Message {
Move(Point),
NoMessage,
}
Then the syntax you wanted will work as-is.
Message::Move(Point { x: 10, y: 15 })
Related
I'm trying to deserialize data in a simple non-human readable and non-self describing format to Rust structs. I've implemented a custom Deserializer for this format and it works great when I'm deserializing the data into a struct like this for example:
#[derive(Serialize, Deserialize)]
pub struct Position {
x: f32,
z: f32,
y: f32,
}
However, let's say this Position struct had a new field added (could have been removed too) in a new version:
#[derive(Serialize, Deserialize)]
pub struct Position {
x: f32,
z: f32,
y: f32,
is_visible: bool, // This field was added in a new version
}
But I still need to support both data from both versions of Position. The version of the data (known at runtime) can be given to the Deserializer but how can the Deserializer know the version of a field (known at compile time)?
I've looked at #[serde(deserialize_with)] but it didn't work because I cannot get the needed version information.
I 've also looked at implementing Deserialize manually for Position and I can receive the versions of the fields of Position by implementing something like Position::get_version(field_name: &str).
However, I cannot figure how to get the version of the data currently being deserialized because Deserialize::deserialize only has a trait bound Deserializer<'de> and I cannot make that bound stricter by adding another bound (so it doesn't know about my custom Deserializer).
At this point, I'm thinking about giving the version data of each field when instantiating the Deserializer but I'm not sure if that will work or if there is a better way to go.
Multiple structs implementing a shared trait
If you have several different versions with several different types of struct, and you want a more robust way of handling different variants, it might be a better idea to write structs for each possible format. You can then define and implement a trait for shared behavior.
trait Position {
fn x(&self) -> f32;
fn y(&self) -> f32;
fn z(&self) -> f32;
fn version_number(&self) -> usize;
}
struct PositionV0 {
x: f32,
y: f32,
z: f32
}
impl Position for PositionV0 {
fn x(&self) -> f32 {
self.x
}
// You get the idea for the fn y, fn z implementations
fn version_number(&self) -> usize {
0
}
}
struct PositionV1 {
x: f32,
y: f32,
z: f32,
is_visible: bool,
}
impl Position for PositionV1 {
fn x(&self) -> f32 {
self.x
}
// You get the idea for the fn y, fn z implementations
fn version_number(&self) -> usize {
1
}
}
Carson's answer is great when you do not have a lot of versions but for me I am working with data structures that range over 20 different versions.
I went with a solution that while I don't think is the most idiomatic, is capable of handling an arbitrary number of versions.
In short:
we implement a Version trait which gives the necessary version info to the Deserializer
Deserializer has VersionedSeqAccess (implements serde::de::SeqAccess) that sets a flag
When flag is set, we put None for that field and immediately unset the flag
The idea is to implement the following trait for the struct:
pub trait Version {
/// We must specify the name of the struct so that any of the fields that
/// are structs won't confuse the Deserializer
fn name() -> &'static str;
fn version() -> VersionInfo;
}
#[derive(Debug, Clone)]
pub enum VersionInfo {
/// Present in all versions
All,
/// Present in this version
Version([u16; 4]),
/// Represent Versions of structs
Struct(&'static [VersionInfo]),
// we can add other ways of expressing the version like a version range for ex.
}
Here is how it will be implemented for the example struct Position. This type of manual deriving is error prone so this can be improved with a derive macro (see end):
struct Position {
x: f32,
z: f32,
y: f32,
is_visible: Option<bool>, // With this solution versioned field must be wrapped in Option
}
impl Version for Position {
fn version() -> VersionInfo {
VersionInfo::Struct(&[
VersionInfo::All,
VersionInfo::All,
VersionInfo::All,
VersionInfo::Version([1, 13, 0, 0]),
])
}
fn name() -> &'static str {
"Position"
}
}
Now, the deserializer will be instansiated with the version of the data format we are currently parsing:
pub struct Deserializer<'de> {
input: &'de [u8],
/// The version the `Deserializer` expect the data format to be
de_version: [u16; 4],
/// Versions of each field. (only used when deserialzing to a struct)
version_info: VersionInfo,
/// Whether to skip deserialzing current item. This flag is set by `VersionedSeqAccess`.
/// When set, the current item is deserialized to `None`
skip: bool,
/// Name of struct we are deserialzing into. We use this to make sure we call the correct
/// visitor for children of this struct who are also structs
name: &'static str,
}
pub fn from_slice<'a, T>(input: &'a [u8], de_version: [u16; 4]) -> Result<T, Error>
where
T: Deserialize<'a> + Version,
{
let mut deserializer = Deserializer::from_slice(input, de_version, T::version(), T::name());
let t = T::deserialize(&mut deserializer)?;
Ok(t)
}
Now that the deserializer has the all the information it needs, this is how we define deserialize_struct:
fn deserialize_struct<V>(
self, name: &'static str, fields: &'static [&'static str], visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if name == self.name {
if let VersionInfo::Struct(version_info) = self.version_info {
assert!(version_info.len() == fields.len()); // Make sure the caller implemented version info somewhat correctly. I use a derive macro to implement version so this is not a problem
visitor.visit_seq(VersionedSeqAccess::new(self, fields.len(), &version_info))
} else {
panic!("Struct must always have version info of `Struct` variant")
}
} else {
// This is for children structs of the main struct. We do not support versioning for those
visitor.visit_seq(SequenceAccess::new(self, fields.len()))
}
}
Here is how serde::de::SeqAccess will be implemented for VersionedSeqAccess:
struct VersionedSeqAccess<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
version_info: &'static [VersionInfo],
len: usize,
curr: usize,
}
impl<'de, 'a> SeqAccess<'de> for VersionedSeqAccess<'a, 'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error>
where
T: DeserializeSeed<'de>,
{
if self.curr == self.len {
// We iterated through all fields
Ok(None)
} else {
// Get version of the current field
let version = &self.version_info[self.curr as usize];
self.de.version_info = version.clone();
// Set the flag if the version does not match
if !is_correct_version(&self.de.de_version, &version) {
self.de.skip = true;
}
self.curr += 1;
seed.deserialize(&mut *self.de).map(Some)
}
}
}
The final part of the puzzle is inside deserialize_option. If we are at a field not found in current data format the skip flag will be set here and we will produce None:
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if self.skip == true {
self.skip = false;
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
A lengthy solution but it works great for my usecase dealing with a lot of structs with lots of fields from different versions. Please do let me know how I can make this less verbose/better. I also implemented a derive macro (not shown here) for the Version trait to be able to do this:
#[derive(Debug, Clone, EventPrinter, Version)]
pub struct Position {
x: f32,
z: f32,
y: f32,
#[version([1, 13, 0, 0])]
is_visible: Option<bool>,
}
With this derive macro, I find that this solution tends to scale well for my usecase.
In my project I'm frequently iterating through a vector of structs to find an object by some field value, then use some trait function on that object:
pub struct Person{
name: String,
age: u32,
id: u32,
}
impl Person{
pub fn new(name: String, id_num: u32, age: u32)->Self{
let p = Person{
name: name,
id: id_num,
age: age,
};
p
}
}
trait PersonTrait{
fn printname();
fn get_name()->String;
fn get_age()->u32;
fn set_age(age: u32);
}
impl PersonTrait for Person{
fn printname(){
dbg!(self.name)
}
fn get_name()->String{
self.name
}
fn get_id()->u32{
self.id;
}
fn set_age(age: u32){
self.age = age;
}
}
fn main(){
let my_people = vec![Person::new("Rakim".to_string(), 1, 56), Person::new("Ghostface".to_string(), 2, 56), Person::new("RZA".to_string(), 3, 56)];
//frequently repeating this pattern of finding struct in array of structs, then doing something to that found struct
for person in my_people.clone(){
if person.get_id() == 1 {
person.set_age(100);
}
}
for person in my_people.clone(){
if person.get_id() == "Rakim".to_string(){
person.printname();
}
}
}
So the general pattern im using here is:
for x in my_objects{
if x.id() == some_id{
x.do_some_trait_function()
}
}
I'd like to create a more general function to make this syntax simpler, something like:
//not sure what the correct syntax would be here, or how you might pass a trait function as an argument
fn find_then_do_trait_function(obj_list: Vec<Person>, id: u32, trait_function: my_trait_function()){
for x in obj_list(){
if x.get_id() == id {
//use my trait function on x
}
}
}
How might I do this? I know I could create an enum for every trait function, then match that enum, but that also seems pretty verbose.
There's nothing unique about trait functions. You've identified a very common pattern which can be split into two pieces: we want to filter a vector and then perform some operation on each matching element. We can define a function that takes two closure arguments to do this for us.
fn search_and_call<T>(obj_list: &mut Vec<T>,
mut condition: impl FnMut(&mut T) -> bool,
mut func: impl FnMut(&mut T) -> ()) {
for x in obj_list {
if condition(x) {
func(x);
}
}
}
func can be any closure. That closure might call a trait function, or it might print to the screen, or do any number of things. The writer of the above function needn't care; it's all the same as far as we're concerned. Sample usage:
let mut v = vec!(1, 2, 3, 4);
search_and_call(&mut v, |x| *x % 2 == 0, |x| println!("{}", *x));
It's worth noting, however, that Rust's excellent Iterator trait defines a ton of useful functions, and we can get this behavior for free, without even touching a for loop.
let mut v = vec!(1, 2, 3, 4);
v.iter().filter(|x| *x % 2 == 0).for_each(|x| println!("{}", *x));
.iter() gets an iterator over our vector, .filter(...) produces a new iterator that selects certain elements based on our condition, and .for_each(...) calls a function on all elements which remain after the filter.
I have a struct:
pub struct Test {
pub x: i32,
pub y: i32,
}
I'd like to have a function that mutates this — easy:
pub fn mutateit(&mut self) {
self.x += 1;
}
This makes the entire struct mutable for the duration of the function call of mutateit, correct? I only want to mutate x, and I don't want to mutate y. Is there any way to just mutably borrow x?
Citing The Book:
Rust does not support field mutability at the language level, so you cannot write something like this:
struct Point {
mut x: i32, // This causes an error.
y: i32,
}
You need interior mutability, which is nicely described in the standard docs:
use std::cell::Cell;
pub struct Test {
pub x: Cell<i32>,
pub y: i32
}
fn main() {
// note lack of mut:
let test = Test {
x: Cell::new(1), // interior mutability using Cell
y: 0
};
test.x.set(2);
assert_eq!(test.x.get(), 2);
}
And, if you wanted to incorporate it in a function:
impl Test {
pub fn mutateit(&self) { // note: no mut again
self.x.set(self.x.get() + 1);
}
}
fn main() {
let test = Test {
x: Cell::new(1),
y: 0
};
test.mutateit();
assert_eq!(test.x.get(), 2);
}
I'm trying to return a vector from a function but the compiler gives me the following error message:
expected `Foo<T>`,
found `Foo<&str>`
(expected type parameter,
found &-ptr) [E0308]
What am I missing here?
struct Foo<T> {
bar: T,
}
fn foos<T>() -> Vec<Foo<T>> {
vec![
Foo { bar: "x" },
Foo { bar: 1 },
]
}
fn main() {
let my_foos: Vec<_> = foos();
println!("{}", my_foos[0].bar);
}
The compiler is giving you a good error message here:
expected `Foo<T>`,
found `Foo<&str>`
That is, you aren't returning some generic T, you are returning a concrete type. Actually, you aren't returning just one type, you are trying to return two different types!
Each time a generic is resolved, it must resolve to a single type. That is, you can call foo<T>(a: T, b: T) with two u32 or two bool, but not with one of each.
To make your code work in the most straight-forward way, you can use an enum. This creates a single type that can have one of a set of values:
struct Foo<T> {
bar: T,
}
#[derive(Debug)]
enum Bar<'a> {
Num(i32),
Str(&'a str),
}
// Note no generics here, we specify the concrete type that this `Foo` is
fn foos() -> Vec<Foo<Bar<'static>>> {
vec![
Foo { bar: Bar::Str("x") },
Foo { bar: Bar::Num(1) },
]
}
fn main() {
let my_foos: Vec<_> = foos();
println!("{:?}", my_foos[0].bar);
}
I want to use trait objects in a Vec. In C++ I could make a base class Thing from which is derived Monster1 and Monster2. I could then create a std::vector<Thing*>. Thing objects must store some data e.g. x : int, y : int, but derived classes need to add more data.
Currently I have something like
struct Level {
// some stuff here
pub things: Vec<Box<ThingTrait + 'static>>,
}
struct ThingRecord {
x: i32,
y: i32,
}
struct Monster1 {
thing_record: ThingRecord,
num_arrows: i32,
}
struct Monster2 {
thing_record: ThingRecord,
num_fireballs: i32,
}
I define a ThingTrait with methods for get_thing_record(), attack(), make_noise() etc. and implement them for Monster1 and Monster2.
Trait objects
The most extensible way to implement a heterogeneous collection (in this case a vector) of objects is exactly what you have:
Vec<Box<dyn ThingTrait + 'static>>
Although there are times where you might want a lifetime that's not 'static, so you'd need something like:
Vec<Box<dyn ThingTrait + 'a>>
You could also have a collection of references to traits, instead of boxed traits:
Vec<&dyn ThingTrait>
An example:
trait ThingTrait {
fn attack(&self);
}
impl ThingTrait for Monster1 {
fn attack(&self) {
println!("monster 1 attacks")
}
}
impl ThingTrait for Monster2 {
fn attack(&self) {
println!("monster 2 attacks")
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things: Vec<Box<dyn ThingTrait>> = vec![Box::new(m1), Box::new(m2)];
}
Box<dyn SomeTrait>, Rc<dyn SomeTrait>, &dyn SomeTrait, etc. are all trait objects. These allow implementation of the trait on an infinite number of types, but the tradeoff is that it requires some amount of indirection and dynamic dispatch.
See also:
What makes something a "trait object"?
What does "dyn" mean in a type?
Enums
As mentioned in the comments, if you have a fixed number of known alternatives, a less open-ended solution is to use an enum. This doesn't require that the values be Boxed, but it will still have a small amount of dynamic dispatch to decide which concrete enum variant is present at runtime:
enum Monster {
One(Monster1),
Two(Monster2),
}
impl Monster {
fn attack(&self) {
match *self {
Monster::One(_) => println!("monster 1 attacks"),
Monster::Two(_) => println!("monster 2 attacks"),
}
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things = vec![Monster::One(m1), Monster::Two(m2)];
}
See also:
Why does an enum require extra memory size?