compiler errors - Spurious requirement for std::marker::Sized -
update: simpler code (play) exhibits same symptoms:
use std::fmt::display; pub fn arg(a: &str, b: &display) { } fn main() { arg("foo", "bar"); } gives error:
<anon>:7:16: 7:21 error: trait `core::marker::sized` not implemented type `str` [e0277] <anon>:7 arg("foo", "bar"); ^~~~~ <anon>:7:16: 7:21 note: `str` not have constant size known @ compile-time <anon>:7 arg("foo", "bar"); ^~~~~ but don't see reason require size here. a , b treated same, same type, , there no problem a. so
- why have problem
b, and - how tell trait not expected have size known.
in fact, it's trait type, never has type known no matter underlying type is. why want size?
oh, , should not forget: in actual use-case need dynamic polymorphism. function (method) chained arguments of different actual types , references stored (see original exhibit below), can't convert t: trait + ?sized.
original exhibit:
i have code following (see on play.rust-lang.org):
pub trait trait { /* methods */ } impl trait str { /* implementation */ } pub struct struct<'a> { args: hashmap<&'a str, &'a trait>, } impl<'a> struct<'a> { pub fn new() -> self { struct { args: hashmap::new() } } pub fn arg(mut self, key: &'a str, value: &'a trait) -> struct<'a> { self.args.insert(key, value); return self; } // of course there process collected arguments } fn main() { struct::new().arg("foo", "bar"); } and gives me error:
test.rs:32:30: 32:35 error: trait `core::marker::sized` not implemented type `str` [e0277] test.rs:32 struct::new().arg("foo", "bar"); ^~~~~ test.rs:32:30: 32:35 note: `str` not have constant size known @ compile-time test.rs:32 struct::new().arg("foo", "bar");
the error not spurious.
the raw representation of trait object (std::raw::traitobject):
#[repr(c)] pub struct traitobject { pub data: *mut (), pub vtable: *mut (), } the actual data of object behind single pointer.
but how dynamically sized types? taking slice (&[t]) example, of form:
#[repr(c)] pub struct slice<t> { pub data: *const t, pub len: usize, } this reference two words: pointer start of slice and number of elements in slice.
the size of &t not constant. if t sized, &t , box<t> 1 word, if t not sized, &t , box<t> two words.
let word = std::mem::size_of::<usize>(); // references sized types: 1 word. assert_eq!(std::mem::size_of::<&()>(), 1 * word); assert_eq!(std::mem::size_of::<&u8>(), 1 * word); assert_eq!(std::mem::size_of::<&string>(), 1 * word); // references unsized types: 2 words. assert_eq!(std::mem::size_of::<&[u8]>(), 2 * word); assert_eq!(std::mem::size_of::<&str>(), 2 * word); assert_eq!(std::mem::size_of::<&std::path::path>(), 2 * word); what impact of this? well, mentioned earlier, definition of trait objects requires data pointer 1 word long. store dynamically sized type require two words there; haven’t given thought practicalities of whether possible inflate trait objects have 2 words data (one of redundant in case of sized objects), might or might not be, language has made decision not support trait objects of dynamically sized types.
therefore: if wish create trait object, need of sized type, such &str, rather dynamically sized type such str. means things (x: &&str) &std::fmt::display;:
arg("foo", &"bar");
Comments
Post a Comment