
to_string() to make the program compile. And I hope to shed some light on the question of why Rust has two string types, String and &str .String . Our search will lead us to the type std::string::String , which is not bad at first. fn print_me(msg: String) { println!(": {}", msg); } fn main() { let message = ", "; print_me(message); } expected `collections::string::String`, found `&'static str` &str not compatible with the type String . We need to change the type of the message variable to String so that the compilation succeeds: let message = ", ".to_string(); . It will work this way, but it's like using clone() to fix ownership-inheritance errors. Here are three reasons to change the type of the print_me argument to &str :& denotes the reference type, that is, we give the variable a loan . When print_me finishes working with a variable, ownership is returned to its original owner. If we don't have a good reason to transfer ownership of the message variable to our function, we should use borrowing.String for message means the program should copy the value. When using a link such as &str , copying does not occur.String can magically turn into &str using the Deref type and type casting. An example will allow to understand this moment much better.print_me function. The main point by which all this works is the transfer of values by reference. Instead of passing the owned string owned_string as a String , we pass it as a &String pointer. When the compiler sees that &String passed to a function that accepts &str , it leads &String to &str . Exactly the same conversion is used when using strings with a normal and atomic reference counter. The variable string already a reference, so there is no need to use & when calling print_me(string) . With this knowledge, we no longer need to constantly call .to_string() on our code. fn print_me(msg: &str) { println!("msg = {}", msg); } fn main() { let string = ", "; print_me(string); let owned_string = ", ".to_string(); // String::from_str(", ") print_me(&owned_string); let counted_string = std::rc::Rc::new(", ".to_string()); print_me(&counted_string); let atomically_counted_string = std::sync::Arc::new(", ".to_string()); print_me(&atomically_counted_string); } Vec . All the same, String is just a vector of eight-byte characters. You can read more about coercion with dereferencing ( English ) in the book “ Rust Programming Language ” ( English ).to_string() . However, we may have some problems when using structures. Using existing knowledge, we could create such a structure: struct Person { name: &str, } fn main() { let _person = Person { name: "Herman" }; } <anon>:2:11: 2:15 error: missing lifetime specifier [E0106] <anon>:2 name: &str, Person cannot survive the name reference. If Person survives the name , there is a risk of the program crashing. The main goal of Rust is to prevent this. Let's make this code compile. We need to specify the time of life ( English ), or scope, so that Rust could provide us security. Typically, the lifetime is called: 'a . I do not know where this tradition came from, but we will follow it. struct Person { name: &'a str,' } fn main() { let _person = Person { name: "Herman" }; } <anon>:2:12: 2:14 error: use of undeclared lifetime name `'a` [E0261] <anon>:2 name: &'a str, Person structure should not survive the name field. So we need to declare the lifetime of the Person structure. Short searches lead us to syntax for declaring the lifetime: <'a> . struct Person<'a> { name: &'a str, } fn main() { let _person = Person { name: "Herman" }; } greet method to our Person class. struct Person<'a> { name: &'a str, } impl Person { fn greet(&self) { println!(", {}", self.name); } } fn main() { let person = Person { name: "Herman" }; person.greet(); } <anon>:5:6: 5:12 error: wrong number of lifetime parameters: expected 1, found 0 [E0107] <anon>:5 impl Person { Person structure has a lifetime parameter, so our implementation should also have it. Let's declare the lifetime 'a in the implementation of Person like this: impl Person<'a> { . Alas, now we get this strange compilation error: <anon>:5:13: 5:15 error: use of undeclared lifetime name `'a` [E0261] <anon>:5 impl Person<'a> { impl like this: impl<'a> Person { . We compile again, we get an error: <anon>:5:10: 5:16 error: wrong number of lifetime parameters: expected 1, found 0 [E0107] <anon>:5 impl<'a> Person { Person structure to its implementation like this: impl<'a> Person<'a> { . Now the program will be compiled. Here is the full working code: struct Person<'a> { name: &'a str, } impl<'a> Person<'a> { fn greet(&self) { println!(", {}", self.name); } } fn main() { let person = Person { name: "Herman" }; person.greet(); } String be used, and when &str in structures? In other words, when should I use a reference to another type in a structure? We should use references if our structure does not require ownership of the variable. The meaning may be slightly blurred, so I use several rules to answer this question. struct Person { name: String, } impl Person { fn greet(&self) { println!(", {}", self.name); } } fn main() { let name = String::from_str("Herman"); let person = Person { name: name }; person.greet(); println!(" {}", name); // move error } Encoder structure does not need to own the variable writer , which implements the type std::fmt::Write , so only borrowing is used. Actually String implements Write . In this example, when using the encode function, a variable of type String passed to the Encoder and then returned back to encode .String buffer with a large amount of data. Copying it every time you transfer to another function can slow down the program significantly.&str , String or even with a reference count. We can also create structures that contain links. The lifetime of the structure is related to the references contained in it, so that the structure cannot survive the variables to which it refers, and thus lead to errors in the program. And now we have a basic understanding of when to use links within structures, and when not.'static lifetime (as in the first example) to make our example compile, but I wouldn’t advise you to do this: struct Person { name: &'static str, } impl Person { fn greet(&self) { println!(", {}", self.name); } } fn main() { let person = Person { name: "Herman" }; person.greet(); } 'static valid throughout the life of the program. You hardly want Person or name live for so long. (For example, static string literals compiled into the program itself have the type &'static str , that is, they live throughout the life of the program - approx. Transl.)Source: https://habr.com/ru/post/274485/
All Articles