I'm trying to implement the Add trait for anything that implements another trait (in the example code the Test trait). I'm using references in the Add implementation because not everything that implements Test will be the same size. The code below compiles fine:
use std::ops::Add;
struct Foo(i32);
struct Bar(i64);
trait Test {}
impl Test for Foo {}
impl Test for Bar {}
impl<'a, 'b> Add<&'b Test> for &'a Test {
type Output = Box<Test>;
fn add(self, other: &'b Test) -> Box<Test> {
if true {
Box::new(Foo(5))
} else {
Box::new(Bar(5))
}
}
}
When I try to actually use Add, as below, it says that the operation could not be applied because the implementation of Add for &Foo is missing.
fn test_add() {
&Foo(5) + &Bar(5)
}
Have I defined the implementation incorrectly? Have I called it incorrectly? The goal is to make the function add take two references to objects which both implement Test, and return a reference (or box) to a new object that implements Test (and might not be the same underlying type as either of the inputs).
I found another approach that changes the behavior slightly, but works.
struct V<T>(T);
use std::ops::Add;
impl<T1: Test, T2: Test> Add<V<Box<T2>>> for V<Box<T1>> {
type Output = V<Box<Test>>;
fn add(self, other: V<Box<T2>>) -> Self::Output {
unimplemented!()
}
}
That allows it to return any type that implements Test, at the cost of wrapping everything in a Box and a dummy struct V. Not very elegant, and I still don't understand why my original code doesn't work, but at least this has the behavior I wanted.
The problem is that the compiler cannot implicitly convert from &Foo into &Test. If you explicitly convert it into &Test first, then the operator overloading works:
fn test_add() {
let foo: &Test = &Foo(5);
foo + &Bar(5);
}
Alternatively, you can use the fully qualified syntax:
fn test_add() {
<&Test as Add<&Test>>::add(&Foo(5), &Bar(5));
}
Related
Based on the following examples, its possible to write a build-pattern with chained method calls in Rust which either passes by value or by reference (with a lifetime specifier)
Is it possible to create a macro to implement builder pattern methods?
How to overload the 'new' method? (top answer)
https://github.com/rust-unofficial/patterns/blob/master/patterns/builder.md
A builder pattern in Rust may look something like this:
ui::Button::new()
.label("Test")
.align(Align::Center)
.build();
When writing idiomatic Rust is there a strong preference for one over another?
Is there some good example of how to write this in Rust?
There are actually two trade-offs:
should the named setter accept self by value or reference?
should the final build method accept self by value or reference?
My recommendation is:
mutable reference for the setters
value for the build method
This differs slightly from the Builder Pattern presented in the Rust Book which uses a reference in build.
Why passing by mutable reference for the setters?
While a compiler may optimize away the moves caused by a call to fn label(self, &str) -> ButtonBuilder, it is not guaranteed.
On the other hand, the mutable reference way is already optimal so that you need not rely on the optimizer.
Why passing by value for the final build?
For builders only composed of Copy fields, there is no difference between build taking self or &self.
However, as soon as the builder contains non-Copy fields, passing &self to build requires deep-cloning these fields.
On the other hand, passing self by value allows build to move the fields, which avoid unnecessary copies.
If one wishes to re-use the builder, then the builder should implement Clone.
I've seen the builder pattern mostly implemented by taking ownership of the Builder when modifying it, and by reference for build(). For example,
#[derive(Debug, Eq, PartialEq)]
struct Foo {
value: usize,
}
struct FooBuilder {
foos: usize,
bars: usize,
}
impl FooBuilder {
fn new() -> FooBuilder {
FooBuilder {
foos: 0,
bars: 0,
}
}
fn set_foos(mut self, foos: usize) -> FooBuilder {
self.foos = foos;
self
}
fn set_bars(mut self, bars: usize) -> FooBuilder {
self.bars = bars;
self
}
fn build(&self) -> Foo {
Foo {
value: self.foos + self.bars,
}
}
}
fn main() {
let foo = FooBuilder::new()
.set_foos(2)
.set_bars(3)
.build();
assert_eq!(foo, Foo { value: 5 });
}
Try on Rust Playground
This makes chaining simple, while allowing reuse of the builder.
I'm new to Rust and have seen some examples of people using Box to allow pushing many types that implement a certain Trait onto a Vec. When using a Trait with Generics, I have run into an issue.
error[E0038]: the trait `collision::collision_detection::Collidable` cannot be made into an object
--> src/collision/collision_detection.rs:19:5
|
19 | collidables: Vec<Box<Collidable<P, M>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `collision::collision_detection::Collidable` cannot be made into an object
|
= note: method `get_ncollide_shape` has generic type parameters
error: aborting due to previous error
error: Could not compile `game_proto`.
To learn more, run the command again with --verbose.
Here is my code
extern crate ncollide;
extern crate nalgebra as na;
use self::ncollide::shape::Shape;
use self::ncollide::math::Point;
use self::ncollide::math::Isometry;
use self::na::Isometry2;
pub trait Collidable<P: Point, M> {
fn get_ncollide_shape<T: Shape<P, M>>(&self) -> Box<T>;
fn get_isometry(&self) -> Isometry2<f64>;
}
pub struct CollisionRegistry<P, M>
where
P: Point,
M: Isometry<P>,
{
collidables: Vec<Box<Collidable<P, M>>>,
}
impl<P: Point, M: Isometry<P>> CollisionRegistry<P, M> {
pub fn new() -> Self {
let objs: Vec<Box<Collidable<P, M>>> = Vec::new();
CollisionRegistry { collidables: objs }
}
pub fn register<D>(&mut self, obj: Box<D>)
where
D: Collidable<P, M>,
{
self.collidables.push(obj);
}
}
I'm trying to use collidables as a list of heterogenous game objects that will give me ncollide compatible Shapes back to feed into the collision detection engine.
EDIT:
To clear up some confusion. I'm not trying to construct and return an instance of a Trait. I'm just trying to create a Vec that will allow any instance of the Collidable trait to be pushed onto it.
Rust is a compiled language, so when it compiles your code, it needs to know all of the information it might need to generate machine code.
When you say
trait MyTrait {
fn do_thing() -> Box<u32>;
}
struct Foo {
field: Box<MyTrait>
}
you are telling Rust that Foo will contain a box containing anything implementing MyTrait. By boxing the type, the compiler will erase any additional data about the data type that isn't covered by the trait. These trait objects are implemented as a set of data fields and a table of functions (called a vtable) that contains the functions exposed by the trait, so they can be called.
When you change
fn do_thing() -> Box<u32>;
to
fn do_thing<T>() -> Box<T>;
it may look similar, but the behavior is much different. Let's take a normal function example
fn do_thing<T>(val: T) { }
fn main() {
do_thing(true);
do_thing(45 as u32);
}
the compiler performs what is a called monomorphization, which means your code in the compiler becomes essentially
fn do_thing_bool(val: bool) { }
fn do_thing_num(val: u32) { }
fn main() {
do_thing_bool(true);
do_thing_num(45 as u32);
}
The key thing to realize is that you are asking it to do the same thing for your trait. The problem is that the compiler can't do it. The example above relies on knowing ahead of time that do_thing is called with a number in one case and a boolean in another, and it can know with 100% certainty that those are the only two ways the function is used.
With your code
trait MyTrait {
fn do_thing<T>() -> Box<T>;
}
the compiler does not know what types do_thing will be called with, so it has no way to generate functions you'd need to call. To do that, wherever you convert the struct implementing Collidable into a boxed object it would have to know every possible return type get_ncollide_shape could have, and that is not supported.
Other links for this:
Understanding Traits and Object Safety
https://www.reddit.com/r/rust/comments/3an132/how_to_wrap_a_trait_object_that_has_generic/
How do I get over something like this:
struct Test {
foo: Option<fn()>
}
impl Test {
fn new(&mut self) {
self.foo = Option::Some(self.a);
}
fn a(&self) { /* can use Test */ }
}
I get this error:
error: attempted to take value of method `a` on type `&mut Test`
--> src/main.rs:7:36
|
7 | self.foo = Option::Some(self.a);
| ^
|
= help: maybe a `()` to call it is missing? If not, try an anonymous function
How do I pass a function pointer from a trait? Similar to what would happen in this case:
impl Test {
fn new(&mut self) {
self.foo = Option::Some(a);
}
}
fn a() { /* can't use Test */ }
What you're trying to do here is get a function pointer from a (to use Python terminology here, since Rust doesn't have a word for this) bound method. You can't.
Firstly, because Rust doesn't have a concept of "bound" methods; that is, you can't refer to a method with the invocant (the thing on the left of the .) already bound in place. If you want to construct a callable which approximates this, you'd use a closure; i.e. || self.a().
However, this still wouldn't work because closures aren't function pointers. There is no "base type" for callable things like in some other languages. Function pointers are a single, specific kind of callable; closures are completely different. Instead, there are traits which (when implemented) make a type callable. They are Fn, FnMut, and FnOnce. Because they are traits, you can't use them as types, and must instead use them from behind some layer of indirection, such as Box<FnOnce()> or &mut FnMut(i32) -> String.
Now, you could change Test to store an Option<Box<Fn()>> instead, but that still wouldn't help. That's because of the other, other problem: you're trying to store a reference to the struct inside of itself. This is not going to work well. If you manage to do this, you effectively render the Test value permanently unusable. More likely is that the compiler just won't let you get that far.
Aside: you can do it, but not without resorting to reference counting and dynamic borrow checking, which is out of scope here.
So the answer to your question as-asked is: you don't.
Let's change the question: instead of trying to crowbar a self-referential closure in, we can instead store a callable that doesn't attempt to capture the invocant at all.
struct Test {
foo: Option<Box<Fn(&Test)>>,
}
impl Test {
fn new() -> Test {
Test {
foo: Option::Some(Box::new(Self::a)),
}
}
fn a(&self) { /* can use Test */ }
fn invoke(&self) {
if let Some(f) = self.foo.as_ref() {
f(self);
}
}
}
fn main() {
let t = Test::new();
t.invoke();
}
The callable being stored is now a function that takes the invocant explicitly, side-stepping the issues with cyclic references. We can use this to store Test::a directly, by referring to it as a free function. Also note that because Test is the implementation type, I can also refer to it as Self.
Aside: I've also corrected your Test::new function. Rust doesn't have constructors, just functions that return values like any other.
If you're confident you will never want to store a closure in foo, you can replace Box<Fn(&Test)> with fn(&Test) instead. This limits you to function pointers, but avoids the extra allocation.
If you haven't already, I strongly urge you to read the Rust Book.
There are few mistakes with your code. new function (by the convention) should not take self reference, since it is expected to create Self type.
But the real issue is, Test::foo expecting a function type fn(), but Test::a's type is fn(&Test) == fn a(&self) if you change the type of foo to fn(&Test) it will work. Also you need to use function name with the trait name instead of self. Instead of assigning to self.a you should assign Test::a.
Here is the working version:
extern crate chrono;
struct Test {
foo: Option<fn(&Test)>
}
impl Test {
fn new() -> Test {
Test {
foo: Some(Test::a)
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
test.foo.unwrap()(&test);
}
Also if you gonna assign a field in new() function, and the value must always set, then there is no need to use Option instead it can be like that:
extern crate chrono;
struct Test {
foo: fn(&Test)
}
impl Test {
fn new() -> Test {
Test {
foo: Test::a
}
}
fn a(&self) {
println!("a run!");
}
}
fn main() {
let test = Test::new();
(test.foo)(&test); // Make sure the paranthesis are there
}
So I have a trait that I want to pass around and do some dynamic method dispatching on. I have one method that needs the trait as a boxed pointer, but it needs to call another method that uses a reference to the trait. So something like:
trait Foo {
fn do_something(&self);
}
struct Bar;
impl Foo for Bar {
fn do_something(&self) {}
}
fn foo_as_box(foo : Box<Foo>) {
foo_as_ref(&foo);
}
fn foo_as_ref(foo : &Foo) {
foo.do_something();
}
fn main() {
let boxed_foo = box Bar as Box<Foo>;
foo_as_box(boxed_foo);
}
But, I get an error on this code
error: failed to find an implementation of trait Foo for Box Foo<no-bounds>
The compiler will convert Box<Foo> into &Foo as needed automatically. You can just say
foo_as_ref(foo);
and it will work.
This doesn't necessarily work in more complex situations. Which is to say, the compiler can't always tell that you want that conversion.
Now that DST has been implemented, you can say &*foo to do the conversion.
In the past the only way to force it was a let-binding, as in
let ref_foo: &Foo = foo;
Of course, your use-case is simple enough that you don't need this.
Suppose I have a rust trait that contains a function that does not take a &self parameter. Is there a way for me to call this function based on a generic type parameter of the concrete type that implements that trait? For example, in the get_type_id function below, how do I successfully call the type_id() function for the CustomType trait?
pub trait TypeTrait {
fn type_id() -> u16;
}
pub struct CustomType {
// fields...
}
impl TypeTrait for CustomType {
fn type_id() -> u16 { 0 }
}
pub fn get_type_id<T : TypeTrait>() {
// how?
}
Thanks!
As Aatch mentioned, this isn't currently possible. A workaround is to use a dummy parameter to specify the type of Self:
pub trait TypeTrait {
fn type_id(_: Option<Self>) -> u16;
}
pub struct CustomType {
// fields...
}
impl TypeTrait for CustomType {
fn type_id(_: Option<CustomType>) -> u16 { 0 }
}
pub fn get_type_id<T : TypeTrait>() {
let type_id = TypeTrait::type_id(None::<T>);
}
Unfortunately, this isn't currently possible. It used to be, based on a implementation detail, however that was removed in favor of eventually implementing a proper way of doing this.
When it is eventually implemented, it may end up looking something like this: TypeTrait::<for T>::type_id(), however there is, currently, no syntax set in stone.
This is a known case and one that is fully intended to be supported, it is just unfortunate that it currently is not possible.
The full discussion about this topic (called associated methods) is here: https://github.com/mozilla/rust/issues/6894 and here: https://github.com/mozilla/rust/issues/8888