From script to library in Rust
In Rust you can write a script or a library. Turning your code into the latter is useful when you want to reuse the code in the script in other projects.
Compare it to a script vs a package in Python. In Python you can write a script and then turn it into a package by adding an __init__.py
file. In Rust you can write a script and then turn it into a library by moving the code into a library project. Let's see how to do this ...
Writing a script
Let's start by writing the simplest script that prints a greeting to the console. And a main function that calls the hello
function with a name:
Create a new project called project
:
cargo new project
And edit the src/main.rs
file to contain the following code:
fn main() {
hello("Alice");
}
fn hello(name: &str) {
println!("Hello, {}!", name);
}
This script defines a hello
function that takes a name as an argument and prints a greeting to the console. The main
function calls the hello
function with the name "Alice" (no command line arguments, this is for example's sake).
Turning the script into a library
To turn the script into a library, we need to create a new library project and move the code from the script into the library. We can do this by running the following commands:
cargo new --lib my_library
mv project/src/main.rs my_library/src/lib.rs
The --lib
flag tells Cargo to create a library project instead of a binary project.
This will create a new library project called my_library
and move the code from the script into the library. The lib.rs
file is the entry point for the library, and it contains the code that will be executed when the library is used.
Using the library
To use the library in the first project, we need to add it as a dependency in the Cargo.toml
file of the project. We can do this by adding the following line to the Cargo.toml
file of the project:
[dependencies]
my_library = { path = "../my_library" }
Normally you would list one or more crates from crates.io in the dependencies
section, but in this case we are using a relative path to the library project.
We can now use the library in the project by importing it and calling the hello function. Create main.rs
again (it was previously moved to the library) under src
in the project and add the following code to it:
use my_library;
fn main() {
my_library::hello("Tim");
}
The path works, because ALE complains about the next thing:
src/main.rs|4 col 17-21 error| E0603: function `hello` is private private function
Rust makes functions private by default. So back in the library I need to make the function public explicitly by adding pub
in front of it in lib.rs
:
pub fn hello(name: &str) {
println!("Hello, {}!", name);
}
And then it works:
$ cargo run -q
warning: function `main` is never used
--> /Users/pybob/code/rust/lib-example/my_library/src/lib.rs:1:4
|
1 | fn main() {
| ^^^^
|
= note: `#[warn(dead_code)]` on by default
Hello, Tim!
I do get this warning that the main
function in the library is never used, which makes sense, because unlike a binary project, the library is not an executable. Therefor I can remove the main
function from the library, no more warnings:
$ cargo run -q
Hello, Tim!
Similar to Python where you can do import pathlib
as well as from pathlib import Path
, you can do the same in Rust. You can import the whole library with use my_library;
or just the hello
function with use my_library::hello;
.
use my_library::hello;
fn main() {
hello("Tim");
}
And that'll work equally well.
Sometimes people opt for the first option, because it's more explicit where the function comes from (my_library::hello
vs hello
). But in this case it's a bit overkill, because there's only one function in the library.
Conclusion
We learned how to make a library as opposed to a script (binary) in Rust (which is what I have mostly done up until this point). This is useful when you want to reuse the code in the script in other projects.
We also learned how to use the library in another project and the fact that Rust makes module functions private by default (another example where it's more strict than Python!)
This is a good thing because it forces you to think about what you want to expose to the outside world.
We also learned about the two ways to import functions from a library: importing the whole library or just the function you need. And lastly the fact that libraries don't have a main
function, because they are not executables.
Now you know how to write libraries in Rust so you can write code that is easier to reuse and maintain. 😍 🎉 📈