A Mech carries a driver, which is a Named entity. At run-time, an omitted Mech constructor consults external source for the specific type of driver to use.
trait Named {
fn name(self) -> String;
}
struct Person {
first_name: String,
last_name: String
}
impl Named for Person {
fn name(self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
Method driver_name returns ownership to a String, for it to be further used in chained calls (in actual code it's a Command). It fails compilation with:
error[E0161]: cannot move a value of type Named + 'a: the size of Named + 'a cannot be statically determined
--> src/lib.rs:22:9
|
22 | self.driver.name()
| ^^^^^^^^^^^
Making the trait Sized fails the object safety:
trait Named: Sized {
fn name(self) -> String;
}
↓
error[E0038]: the trait `Named` cannot be made into an object
--> src/lib.rs:17:5
|
17 | driver: Box<Named + 'a>,
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Named` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
Is there a way to make this pattern happen?
Is there anything fundamental that I seem to be missing?
In case this is impossible to achieve, what's a good way to work around it?
As the compiler hinted, the trait cannot be statically determined because you are dealing with dynamic dispatch. Ownership is still possible in this scenario using self: Box<Self>.
trait Named {
fn name(self: Box<Self>) -> String;
}
struct Person {
first_name: String,
last_name: String,
}
impl Named for Person {
fn name(self: Box<Self>) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
fn main() {}
Related
I'm trying to create an iterator that will add one element to the start of a vector
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> ???
}
I understand I need to use the chain function for this but I'm not sure how, or what will the return type be
Maybe someone can explain to me how to use it?
The exact types of iterators can be complex. A fast way to determine them is to try to return the wrong type on purpose, and see what the compiler says:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> () {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
(Permalink to the playground)
This gives:
error[E0308]: mismatched types
--> src/lib.rs:10:9
|
9 | pub fn all_objects(&mut self) -> () {
| -- expected `()` because of return type
10 | std::iter::once(&self.player).chain(self.npcs.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
| |
| expected `()`, found struct `std::iter::Chain`
|
= note: expected unit type `()`
found struct `std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>>`
and indeed if you replace that, it will compile:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(
&mut self,
) -> std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>> {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
But the exact type usually doesn't matter with iterators, so you can simply specify that your function returns some kind of iterator:
struct Object;
struct World {
player: Object,
npcs: Vec<Object>,
}
impl World {
pub fn all_objects(&mut self) -> impl Iterator<Item = &Object> {
std::iter::once(&self.player).chain(self.npcs.iter())
}
}
(Permalink to the playground)
This is also more flexible, as it will let you change the implementation without affecting the users of the function.
I'm having trouble understanding traits and object safety in Rust.
I have a StoreTrait for storing some data and a Resource struct that holds a reference to a StoreTrait.
I want the Resource to have a reference to a store intance, because many of the methods of Resource will use store, and I don't want to explicitly pass store to every method on Resource.
I also need to have the logic reside in the trait, because I have various impls that will need to share it (an in-memory and an on-disk store). So moving it into the impl is not what I'd prefer.
In the Store trait, I try passing &Self to a function, but it fails because &Self is not Sized:
pub trait StoreTrait {
fn create_resource(&self) {
let agent = Resource::new(self);
}
}
struct Resource<'a> {
store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/lib.rs:3:35
|
3 | let agent = Resource::new(self);
| ^^^^ doesn't have a size known at compile-time
|
= note: required for the cast to the object type `dyn StoreTrait`
help: consider further restricting `Self`
|
2 | fn create_resource(&self) where Self: Sized {
| ^^^^^^^^^^^^^^^^^
This is where this might become an XY problem
The compiler suggests using where Self: Sized bounds in these methods.
However, this causes another problem later when calling save_resource() from a Resource, since that means I'm invoking a method on a trait object with a Sized bound.
pub trait StoreTrait {
// So after adding the trait bounds here...
fn create_resource(&self)
where
Self: Sized,
{
let agent = Resource::new(self);
}
// And here (internal logic requires that)...
fn save_resource(&self, resource: Resource)
where
Self: Sized,
{
// This now requires `Self: Sized`, too!
self.create_resource()
}
}
pub struct Resource<'a> {
pub store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
pub fn save(&self) {
self.store.save_resource(self)
}
}
playground
error: the `save_resource` method cannot be invoked on a trait object
--> src/lib.rs:26:20
|
13 | Self: Sized;
| ----- this has a `Sized` requirement
...
26 | self.store.save_resource(self)
| ^^^^^^^^^^^^^
How do I circumvent setting the trait bound? Or how do I prevent calling a method on a trait object? Perhaps I'm doing something else that doesn't make a ton of sense?
edit: I ended up changing the arguments for the functions. Whenever I used &dyn StoreTrait, I switched to &impl StoreTrait. This means the functions with that signature are compiled for every implementation, which makes the binary a bit bigger, but it now works with the sized requirement. yay!
Perhaps if you just move function from the trait to each implementation it will do what you want?
fn main() {}
pub trait StoreTrait {
fn create_resource(&self);
fn save_resource(&self, resource: &Resource);
}
struct Resource<'a> {
store: &'a dyn StoreTrait,
}
impl<'a> Resource<'a> {
pub fn new(store: &dyn StoreTrait) -> Resource {
Resource { store }
}
pub fn edit(&self) {
self.store.save_resource(self)
}
}
struct StoreMem {
resources: Vec<String>,
}
impl StoreTrait for StoreMem {
fn create_resource(&self) {
let agent = Resource::new(self);
}
fn save_resource(&self, resource: &Resource) {
//
}
}
struct StoreDisk {
resources: Vec<String>,
}
impl StoreTrait for StoreDisk {
fn create_resource(&self) {
let agent = Resource::new(self);
}
fn save_resource(&self, resource: &Resource) {
//
}
}
I am writing a struct that functions as a thin wrapper over an existing struct. The existing struct isn't fixed, so I've written it as a type parameter (see struct B below). I would like B to preserve convertibility (i.e. From/Into) based on the internal wrapped type, i.e. if A1 is convertible to A then B<A1> should be convertible to B<A> as well.
I tried the following code:
pub struct A {}
pub struct A1 {}
impl From<A1> for A {
fn from(a1: A1) -> Self {
Self {}
}
}
pub struct B<T> {
t: T,
other_stuff: String,
}
impl<T, U: Into<T>> From<B<U>> for B<T> {
fn from(b: B<U>) -> Self {
Self {
t: b.t.into(),
other_stuff: b.other_stuff,
}
}
}
pub fn main() {
// I would like this to work:
let ba1: B<A1> = B{ t: A1{}, other_stuff: "abc".to_owned() };
let ba: B<A> = ba1.into();
}
It produces a compilation error:
error[E0119]: conflicting implementations of trait `std::convert::From<B<_>>` for type `B<_>`:
--> src/main.rs:13:1
|
13 | impl<T, U: Into<T>> From<B<U>> for B<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
I think I understand why the error arises (because converting B<A> to B<A> is already defined), but how may I rewrite my code to avoid the error?
I have a Student struct which I store in a HashSet inside a School struct wrapped by Rc references so that they can be referenced by other internal structures in School:
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(Debug, Eq)]
struct Student {
id: usize,
// other stuff
}
impl Hash for Student {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl PartialEq for Student {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
struct School {
students: HashSet<Rc<Student>>,
// other stuff
}
impl School {
fn new() -> Self {
Self {
students: HashSet::new(),
}
}
fn add_student(&mut self) -> usize {
let id = self.students.len();
self.students.insert(Rc::new(Student { id }));
id
}
}
I wanted to implement Borrow<usize> for Rc<Student> so I could get references to students from the HashSet using their id:
use std::borrow::Borrow;
impl Borrow<usize> for Rc<Student> {
fn borrow(&self) -> &usize {
&self.id
}
}
impl School {
fn enrol(&mut self, student_id: usize) {
// Need trait Borrow<usize> implemented for Rc<Student> for this to work
if let Some(student) = self.students.get(&student_id) {
println!("Enrolling {:?}", student);
}
}
}
Unfortunately I can't do that as Borrow is defined elsewhere, and the compiler is telling me I need to create a new type.
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:26:1
|
26 | impl Borrow<usize> for Rc<Student> {
| ^^^^^-------------^^^^^-----------
| | | |
| | | `std::rc::Rc` is not defined in the current crate
| | `usize` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
I understand why a direct implementation of Borrow for Rc<T> is not possible but I'm wondering if there is a better way other than defining a new type just so I can implement Borrow. The goal is to have a shared reference but still be able to get objects from the HashSet by their id? Perhaps Rc isn't the best option here?
I want to implement getter and setter into the trait. For example:
trait StringValue {
value: String;
fn setValue(&self, value: String) {
self.value = value;
}
fn getValue(&self) -> String {
return self.value;
}
}
struct S;
impl StringValue for S {}
fn main() {
let s: S = S {};
s.setValue(String::from("test"));
println!("{}", s.getValue());
}
cargo build:
error: missing `fn`, `type`, or `const` for trait-item declaration
--> src/main.rs:1:20
|
1 | trait StringValue {
| ____________________^
2 | | value: String;
| |____^ missing `fn`, `type`, or `const`
error[E0609]: no field `value` on type `&Self`
--> src/main.rs:5:14
|
5 | self.value = value;
| ^^^^^
error[E0609]: no field `value` on type `&Self`
--> src/main.rs:9:21
|
9 | return self.value;
| ^^^^^
error: aborting due to 3 previous errors
Questions:
Can I use parameters into traits?
How can I fix the code?
If I want to use getter and setter into two different classes, how to implement it?
There is no way to do this in Rust (Currently). However, it's very likely that an alternative, similar, solution is enough for you. If you're interested in progress in that feature, you can check out https://github.com/rust-lang/rfcs/pull/1546 and https://github.com/nikomatsakis/fields-in-traits-rfc.
As for alternative solutions, simply leaving the implementation of the getter/setter to the struct is one option:
trait StringValue {
fn setValue(&mut self, value: String);
fn getValue(&self) -> &String;
}
struct S {
value: String,
}
impl StringValue for S {
fn setValue(&mut self, value: String) {
self.value = value;
}
fn getValue(&self) -> &String {
return &self.value;
}
}
fn main() {
let mut s: S = S {
value: String::from(""),
};
s.setValue(String::from("test"));
println!("{}", s.getValue());
}
But that might get slightly repetitive, specially if you have many such methods. You could try putting them in a separate state struct, add a getter for that state struct and use it to get the fields in the trait's default impl for all the getters/setters, and then just leave an impl of the getter for the state struct up to the containing one to define. However, it should be noted that if you expect these getter/setters to be flexible and be "overriden" (Not use the default), adding the intermediate State struct will make it so a struct overriding the default impl (For, say, get_value in the example with a constant string) needs/has an unused field in the State struct.Example:
trait StringValue {
fn get_state(&self) -> &State;
fn get_state_mut(&mut self) -> &mut State;
fn set_value(&mut self, value: String) {
self.get_state_mut().value = value
}
fn get_value(&self) -> &str {
self.get_state().value.as_str()
}
fn set_value2(&mut self, value: String) {
self.get_state_mut().value2 = value
}
fn get_value2(&self) -> &str {
self.get_state().value2.as_str()
}
}
struct State {
value: String,
value2: String,
}
struct OtherStruct {
state: State,
}
impl StringValue for OtherStruct {
fn get_state_mut(&mut self) -> &mut State {
&mut self.state
}
fn get_state(&self) -> &State {
&self.state
}
}
fn main() {
let mut s = OtherStruct {
state: State {
value: String::from(""),
value2: String::from(""),
},
};
s.set_value(String::from("test"));
dbg!(s.get_value());
s.set_value2(String::from("test2"));
dbg!(s.get_value2());
}
As mentioned by Ömer Erden, the https://crates.io/crates/getset crate might be useful.
From my experiment, getset crate doesn't work, because one has to implement the getter and setters in the impl Trait for Struct block, instead of the Struct block.
To get rid of the repetitive getter/setting implementation, you can use a macro. It is the easiest type of macro to write because you don't even need to process any tokens.
Say you have a struct and trait like below:
trait Test {
fn get_a(&self) -> i32;
fn get_b(&self) -> i32;
}
struct TT {
a: i32,
b: i32,
}
All you need to do is this:
macro_rules! getters {
{} => {
fn get_a(&self) -> i32 {
self.a
}
fn get_b(&self) -> i32 {
self.b
}
}
}
Then you can spam the getters!(); macro inside the impl block for any struct implementing Test trait.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d897baa26b8c32e5e7bde6c596714353