Cannot get out of borrowed content when borrowing generic type

I have a program more or less like this

struct Test<T> { vec: Vec<T> } impl<T> Test<T> { fn get_first(&self) -> &T { &self.vec[0] } fn do_something_with_x(&self, x: T) { // Irrelevant } } fn main() { let t = Test { vec: vec![1i32, 2, 3] }; let x = t.get_first(); t.do_something_with_x(*x); } 

Basically, we call the struct Test method, which takes some value. Then we call another method in the same structure, passing the previously obtained value.

This example works great. Now that we create the main generic content, it no longer works.

 fn generic_main<T>(t: Test<T>) { let x = t.get_first(); t.do_something_with_x(*x); } 

Then I get the following error:

error: cannot exit borrowed content

src / main.rs: 14 let raw_x = * x;

I'm not quite sure why this is happening. Can someone explain to me why Test<i32> not borrowed when calling get_first , but Test<T> ?

+5
source share
1 answer

The short answer is that i32 implements the Copy attribute, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>) , your immediate problem will be fixed.

The longer answer is that Copy is a special feature, which means that values ​​can be copied by simply copying bits. Types like i32 implement Copy . Types such as String do not implement Copy because, for example, this requires heap allocation. If you copied String only by copying the bits, you will get two String values ​​pointing to the same piece of memory. That would be bad (it’s not safe!).

Therefore, providing your T a Copy binding is pretty restrictive. A less restrictive assessment would be T: Clone . The Clone character is similar to Copy (in that it copies the values), but usually this is not done simply by “copying bits”. For example, the String type implements Clone , creating a new heap allocation for base memory.

This requires you to change your generic_main text:

 fn generic_main<T: Clone>(t: Test<T>) { let x = t.get_first(); t.do_something_with_x(x.clone()); } 

Alternatively, if you do not want to have Clone or Copy borders, you can change your do_something_with_x method to get a reference to T , not to the one belonging to T :

 impl<T> Test<T> { // other methods elided fn do_something_with_x(&self, x: &T) { // Irrelevant } } 

And your generic_main remains basically the same, except that you are not looking for x :

 fn generic_main<T>(t: Test<T>) { let x = t.get_first(); t.do_something_with_x(x); } 

Read more about Copy in the documentation . There are some good examples, including how to implement Copy for your own types.

+10
source

Source: https://habr.com/ru/post/1213655/


All Articles