A value of type `x` is not used for type` x`

When compiling the following code:

trait RenderTarget {} struct RenderWindow; impl RenderTarget for RenderWindow {} trait Drawable { fn draw<RT: RenderTarget>(&self, target: &mut RT); } fn main() { let mut win = RenderWindow; let mut vec: Vec<Box<Drawable>> = Vec::new(); for e in &vec { e.draw(&mut win); } } 

I get an error message:

 error: the trait `Drawable` is not implemented for the type `Drawable` [E0277] src/main.rs:15 e.draw(&mut win); ^~~~~~~~~~~~~~ 

What error message is trying to say? Also, how to fix it?

There is a related question , but the solution was to change the A trait (which corresponds to Drawable in my case), but this is not possible here since Drawable is from an external library.

+8
generics traits compiler-errors rust
source share
3 answers

Update: fixed object security rules for version 1.0. Namely, by the value of self the method object is unsafe.

This error occurs due to the security of objects .

To create a feature object from a feature, this feature must be object-safe. A symptom is object-safe if both of these statements are preserved:

  • it does not have a Sized requirement, as in trait Whatever: Sized {} ;
  • all of its methods are object-safe.

A method is object-safe if both of these statements are true:

  • it has a requirement where Self: Sized , as in fn method() where Self: Sized ;
  • none of the following statements are true:

    • this method mentions self in its signature in any form, even by reference, except for associated types;
    • this method is static;
    • This method is common.

These limitations are actually quite natural if you think more about them.

Remember that when values ​​are entered into objects of objects, the actual information of their type is erased, including their size. Therefore, object objects can only be used through a link. References (or other smart pointers, such as Box or Rc ), when applied to feature objects, become "fat pointers" - together with a pointer to a value, they also contain a pointer to a virtual table for that value.

Since object objects can be used only through a pointer, self value methods cannot be called on them - to call such methods you will need the actual value. This was a violation of the object’s security at some point, which meant that traits with such methods could not be trait objects, but even before 1.0 the rules were changed to allow self methods on object objects. However, these methods cannot be called, for the reason described above. There is reason to expect that this restriction will be lifted in the future, as it currently leads to some quirks in this language, for example, the inability to call Box<FnOnce()> closures.

self cannot be used in methods that should be called on object objects precisely because object objects have their actual type, but to call such methods, the compiler needs to know this erased type.

Why static methods cannot be called on object objects, I think it’s obvious: static methods by definition "belong" to the attribute itself, and not to the value, so you need to know the specific type that implements the trait call them. More specifically, regular methods are sent through a virtual table stored inside the object-object, but static methods have no receiver, so they have nothing to send, and for this reason they cannot be stored in the virtual table. Thus, they are unacceptable without knowing the specific type.

General methods of signs cannot be called for another reason, more technical than logical, I think. In Rust, common functions and methods are implemented through monomorphization, i.e. For each instance of a generalized function with a specific set of type parameters, the compiler generates a separate function. For the user of the language, it looks like they call a common function; but at the lowest level, for each set of type parameters there is a separate copy of a function specialized for working with type instances.

Given this approach, in order to call common methods for an object-object, you will need its virtual table to contain pointers to almost all kinds of instances of a universal method for all possible types, which, of course, is impossible, since it will require an infinite number of instances. And therefore, calling common methods of object objects is prohibited.

If Drawable is an external sign, then you are stuck - it is impossible to do what you want, that is, call draw() for each element in a heterogeneous collection. If your drawing set is statically known, you can create a separate collection for each drawable type or, alternatively, create your own enum , which will contain an option for each selected type. Then you can implement Drawable for the enumeration itself, which would be pretty simple.

+6
source share

I am talking about Vladimir’s excellent answer, which explains the safety of the facility, but I’m afraid that in the middle of the discussion a specific problem was forgotten.

As Vladimir mentions, the problem is that the method, which is common to types (common in terms of life is exact), shows that it belongs to unsuitable for polymorphism at runtime; this, in Rust, is called Object Security.

The simplest solution is to remove the general method parameter!

 trait RenderTarget {} struct RenderWindow; impl RenderTarget for RenderWindow {} trait Drawable { fn draw(&self, target: &mut RenderTarget); } fn main() { let mut win = RenderWindow; let mut vec: Vec<Box<Drawable>> = Vec::new(); for e in &vec { e.draw(&mut win); } } 

The main difference between:

 fn draw<RT: RenderTarget>(&self, target: &mut RT) 

and

 fn draw(&self, target: &mut RenderTarget) 

is that the latter requires that the RenderTarget also be Object Safe, since it is now used in a polymorphism situation at runtime (so there is no static method, no general method, no Self , ...).

Another (more technical) difference is that the former is "monomorphized" at compile time (that is, RT is replaced by the real type and all applicable optimizations), while the latter is not (and therefore optimization).

+3
source share

If you are stuck in what is given to you, there are two options that you could try.

In this case, you cannot, but if you were given a non-standard RenderTarget

 trait Drawable { fn draw<RT: RenderTarget + ?Sized>(&self, target: &mut RT); } 

you could implement

 trait DrawableDynamic { fn draw(&self, target: &mut RenderTarget); } impl<T: Drawable> DrawableDynamic for T { fn draw(&self, target: &mut RenderTarget) { Drawable::draw(self, target) } } 

to redirect the types that you have provided, alternatively with the dynamic dispatch of objects. It seems that such a change can be made upstream, since you cannot use the fact that the size is RT .

The other does not allow you to put an arbitrary Drawable into your Vec , but should work without allowing custom types upstream. You need to use this enumeration to wrap the possible values ​​of the vector:

 enum AllDrawable { Square(Square), Triangle(Triangle) } impl Drawable for AllDrawable { fn draw<RT: RenderTarget>(&self, target: &mut RT) { match *self { AllDrawable::Square(ref x) => x.draw(target), AllDrawable::Triangle(ref x) => x.draw(target), } } } 

One could add From implementations, etc .; it might be easier for you if you use wrapped_enum! which will automatically implement them for you.

+2
source share

All Articles