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:

  1. The manual will be&strintoStringType is a hassle, and that’s what you want to achieve prettyAPIThe big obstacle
  2. Should you let the users of the interface decide how to create proprietary data, rather than simply receiving it around&strType 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