Ref :: doesn't have size known at compile-time


#1
  1. Consider this snippet:
se super::*;


pub trait FooT {}


pub struct Bar<'a, Storage> {
    pub x: i32,
    pub foo: &'a Storage
}

pub struct Cat<'a> {
    pub bar: Bar<'a, FooT>
}

#[test]
fn test_00() {

}
  1. Rustc is complaining that:
   |
13 |     pub bar: Bar<'a, FooT>
   |     ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time

But this makes no sense to me: because although we don’t know the size of the object that implements trait FooT, we don’t really care as we have

pub foo: &'a Storage

so we store a reference to FooT rather than an object that implements FooT, and, afaik, all references have the same size.

  1. What am I doing wrong, and how do we fix this?

#2

You need to indicate that Storage can be an unsized type:

pub struct Bar<'a, Storage: ?Sized>

#3

@vitalyd : Thanks! This fixed it. However, I have no idea what I did wrong / what assumption was incorrect / what’s going on behind the scenes? Can you point me at docs for this?


#4

(Preferably something explaining it from the perspective of the compiler / typ checker.)


#5

Sized is a default constraint for all types, and because of this you have to opt-out of using sized by using ?Sized. This auto-bound is for ergonomics, because in most cases your types will be Sized.

https://doc.rust-lang.org/std/marker/trait.Sized.html


#6

Sorry if this sounds stupid – most of the time, traits seem to be “Additive” in that we say: in addition to whatever we know about this object, we ALSO know that it satisfies this other property.

?Sized seems to be subtractive, in that we look at objects (which by default are all Sized ?) and then we are saying: we have no idea what the size of the object is?


#7

?Sized isn’t really subtractive, but it does remove that default. If you combine it with something else that must be sized, like ?Sized + Default, then the result will still have to be Sized.