24 days from Node.js to Rust
preface
So far, you’ve learned enough to start writing apis, and when you try, you might run into a similar problem: You implement a function that takes a string as an argument, and the code might look something like this:
fn my_beautiful_function(arg1: String, arg2: String, arg3: String) {
/ *... * /
}
Copy the code
This is what you need to do when calling this interface:
my_beautiful_function(
"first".to_owned(),
"second".to_owned(),
"third".to_owned()
);
Copy the code
This interface is poorly implemented because every time you call this interface you need to call.to_owned().
The body of the
& STR with String
What we need to ask ourselves is, do we really need to take ownership or borrow?
Use type
If you don’t need to take ownership of the data, then set the parameter to a reference type and the question becomes: &str or &string? The answer is usually &str. Let’s look at this code:
fn print_str(msg: &str) {
println!("{}", msg);
}
Copy the code
You can pass a String literal directly, or you can pass an &String:
fn main() {
let string_slice = "String slice assigned to variable";
let real_string = "Genuine String".to_owned();
print_str(string_slice);
print_str("Literal slice");
print_str(&real_string);
}
Copy the code
Wherever you need an ampersand STR, you can use ampersand without any problems, but the reverse is not true. If you change the function definition to accept variables of type ampersand String, the compiler will raise an error when you pass an ampersand STR argument
Ownership type
If you need a String with ownership, consider the following:
- The manual will be
&str
intoString
Type is a hassle, and that’s what you want to achieve prettyAPI
The big obstacle - Should you let the users of the interface decide how to create proprietary data, rather than simply receiving it around
&str
Type variables and then convert them yourself
Do you want your interface to handle &str and String at the same time? If so, you need to look for common ground between the two, which we’ll explain in more detail below
Any type
For a function that wants to take an arbitrary string, we can take an argument that implements the ToString method:
se std::str::FromStr; // Imported to use Ipv4Addr::from_str
fn main() {
let ip_address = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap();
let string_proper = "String proper".to_owned();
let string_slice = "string slice";
needs_string(string_slice);
needs_string("Literal string");
needs_string(string_proper);
needs_string(ip_address);
}
fn needs_string<T: ToString>(almost_string: T) {
let real_string = almost_string.to_string();
println!("{}", real_string);
}
Copy the code
Here’s the new syntax, generics. The needs_string function above could also be written like this:
fn needs_string(almost_string: impl ToString) {
let real_string = almost_string.to_string();
println!("{}", real_string);
}
Copy the code
So what’s the difference? Whereas generics are more powerful than IMPl [traits], Rust provides the where keyword to do the same:
fn needs_string<T>(string: T)
where
T: ToString,
{
println!("{}", string);
}
Copy the code
The where syntax is no different from the
syntax
Both ampersand STR or String are received
You won’t lose too much if you don’t read this section, since the ToString method covers most cases, but you do expose API users to the same problems we did in tutorial 6 with.to_string() to convert & STR ToString. Many structures implement Display, and a user can pass a large number of objects to a function without the compiler giving an error. In addition, implementing.to_string() sometimes has a cost. The user doesn’t necessarily know how the API works, so you might have to do a lot of extra work
Since we already know that &String can replace & STR, we can generalize the input to anything that can be referenced, such as a STR
Compared with Borrow< STR >, we are more inclined to AsRef< STR >, because the former has more assumptions and is easy to fail, while the latter has fewer assumptions and is not easy to fail. There are more differences, but we won’t use them here
The following code is similar to the previous one, but ip_address is not a valid argument, because just because it has a printable string does not mean it can be treated like & STR
reading
- The Rust Book: ch 10
- Rust by Example: Generics
- The Rust Reference: Generic Parameters
conclusion
It was naive to think that strings in Rust were simple, but strings in JavaScript are much simpler than Rust. But as you learn more, you’ll come to appreciate the beauty of Rust’s design for security and speed
In the next article, we’ll start learning about error handling
More and more
- Rust tutorial (1) From NVM to Rust
- Rust tutorial (2) from NPM to Cargo for the front end
- Configure Visual Studio Code in Rust (3)
- Rust tutorial (4) Hello World
- Rust Tutorial for the front end (5) Borrowing & Ownership
- Part 1 of Rust Tutorial (6) String
- Rust Tutorial (7)
- Rust Tutorial (8)
- Rust Tutorial (9)
- Rust tutorial for the front end (10) from Mixins to Traits
- Rust Tutorial (11) Module for the front-end
- Part 2 of Rust Tutorial (12) String
- Rust Tutorial (13) Results & Options