问题
Below is a Maven/Java directory structure.
- src
- main
- java
- resources
- test
- java
- resources
- target
Here, the resources folder holds application-related configuration files and resource files, to avoid hard-coding their contents in source files.
How can I achieve the same in Rust with Cargo?
回答1:
Maven doesn't include everything from your source. In fact, it includes the binary but doesn't even have to include the source at all in a .jar
. You can configure it to say what to include, which by default is everything in the resources
directory.
Cargo packages source code. Everything will be included in the crate, with the exception of things that match your .gitignore
file. You can fine-tune that in your Cargo.toml
file, by adding an include or exclude entry in the [package]
section.
To access these files, there are a few options.
For example, if your project looks like this:
- Cargo.toml
- src
- main.rs
- resources
- hello.txt
There are three main ways to access hello.txt
, as follows.
The include!
macro
With the include!
macro, you can access hello.txt
from main.rs
like this:
let hello: &str = include!("../resources/hello.txt");
Be aware that the macro will include the file directly in the source, exactly as if you copy & pasted the contents of the file. So the example I gave there would work only if the contents of the file include ""
quotes. Any Rust source can go there, and it has to be included at compile-time. This can be convenient for including complicated Rust structs, without having to write parsing code. Notice that the path is relative to the source .rs
file that included it.
The include_bytes!
and include_str!
macros
The include_bytes!
macro creates a fixed-size array of u8
from the file, to be included at compile-time.
let bytes = include_bytes!("../resources/hello.txt").
let hello: String = String::from_bytes_lossy(bytes).to_string();
This is convenient for incorporating arbitrary binary data into your application, for example an image, without having to load it at runtime. The array has 'static
lifetime, so will stay in memory for the entire lifetime of your application.
The include_str!
macro works similarly, but will result in a string slice, also with 'static
lifetime.
At runtime
To load a file at run-time, you can use:
let mut contents: String = String::new();
let mut file: File = File::open("resources/hello.txt").unwrap();
file.read_to_string(&mut contents).unwrap();
let hello = contents;
The path here is relative to the root of your crate. This assuming that you are running the application with cargo run
from where it was built. If you are deploying a binary, you may have to supply a path to where your application should find its resources.
Usually, this is the preferred method. It's more flexible as you can swap the config at runtime or use application arguments to load from a different location. There are lots of crates for parsing different file formats, including json, toml and plenty of others. You have control over the lifetime of the data you load, so you can make sure it's deallocated when you are finished with it.
来源:https://stackoverflow.com/questions/46486134/how-to-avoid-hard-coded-values-in-rust