How to avoid hard-coded values in Rust

Deadly 提交于 2020-06-26 04:48:09

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!