Why str type is unknown at compile time?Here the variable v is &str but when we passing to name field it becomes str.How is that possible?

fn main(){ 
    let v="aniana";
    let two=PersonOne{name:v};
}

struct PersonOne<'a,T>{
    name:&'a T
}

The compiler is "solving" the "equation" &'static str = &'a T, because of the value you used as name. The result is that 'a == 'static and that T == str.

A few notes:

  • You don't need to put your entire question in the title.
  • It often helps to include the full error message you got from the compiler.

I think you have misunderstood the error the compiler gave you. Here is the error:

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --> src/main.rs:3:28
  |
3 |     let two=PersonOne{name:v};
  |                            ^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `str`

Note that it says "the size for values of type str cannot be known at compile time". The problem here is specifically the size of str, not that the type is str.

This is a problem because any given str could be any size. The compiler can represent a &str, because those are always the same size (one pointer and one length). However, it can't represent a str directly, because it could be five bytes (for "hello"), or 35 bytes (for "dynamically sized types are strange"), or 0 bytes (for "").[1] Types like this are called "dynamically sized" and have extra limitations on them. Types where the compiler definitely knows their size are called "Sized".

"But, the compiler knows the size of "aniana"! What's the problem?"

str represents all strings, no matter how long they are. Rust does not have types for strings of a specific length. So, although the compiler knows how long a specific string is, that length cannot be represented in a type.

When you write struct PersonOne<'a, T> { ... }, the generic type T is assumed to be sized. This is because you almost always want to deal with sized types. As a result, when you do PersonOne { name: v } the compiler deduces that T = str. T requires a sized type, but str is not sized, so the compiler errors.

If you want to allow dynamically sized types, you need to change your code to this:

fn main() {
    let v = "aniana";
    let two = PersonOne { name: v };
}

struct PersonOne<'a, T: ?Sized> {
    name: &'a T,
}

Note the use of : ?Sized. This tells the compiler that it isn't allowed to assume that T is sized. Thus, str is a valid type to use here.


  1. To expand a little: the compiler has to be able to reserve space for stack variables, function arguments, return values, struct fields, and so on. It cannot do this if it doesn't know how many bytes to reserve. â†Šī¸Ž

6 Likes

May I ask you a question? Why don't you just use a standart String implementation?
It helps to escape theese problems cause its free of any linkers. I usually use it, correct me if I'm wrong

1 Like

It's common that users that just started to learn Rust want to use references rather than owned types because they want to "extract" all the performance out of their code. The problem is that they attempt to do it before having a good grasp of intricacies such as how the borrow checker works, sized vs unsized types, etc.

2 Likes

Another way to get the code to compile is to change name: &'a T to just name: T. That way, when assigning a &str to name, the compiler won't try to "unwrap" the reference to determine the type of T; it'll instead determine that T is &str, which is already Sized.

fn main() {
    let v = "aniana";
    let two = PersonOne { name: v };
}

struct PersonOne<T> {
    name: T,
}

initially let v="anaina" ,here v is in &str type.But in the next line we passes the v to name field, how it becomes str here?

Check this thread from this morning from another user who had exactly the same question: String literal in struct.

1 Like