Hands-On Data Structures and Algorithms with Rust
上QQ阅读APP看书,第一时间看更新

Dependencies

This is probably the most important section for most developers. The dependencies section contains a list of values that represent crate names on crates.io (or your configured private registry) as keys along with the version as values.

Instead of the version string, it's equally possible to provide an inline table as a value that specifies optionality or other fields:

[dependencies]
hyper = "*"
rand
= { version = "0.5", optional = true }

Interestingly, since this is an object, TOML allows us to use it like a section:

[dependencies]
hyper
= "*"

[dependencies.rand]

version = "0.5"
features = ["stdweb"]

Since, in the 2018 edition, the extern crate declarations inside the .rs files are optional, renaming a dependency can be done inside the Cargo.toml specification by using the package property. Then, the specified key can become an alias for this package, like this:

[dependencies]
# import in Rust with "use web::*"
web
= { version = "*", package = "hyper" }

[dependencies.random] # import in Rust with "use random::*"

version = "0.5"
package = "rand"
features = ["stdweb"]

Features are crate-specific strings that include or exclude certain features. In the case of rand (and some others), stdweb is a feature that allows us to use the crate in Wasm scenarios by leaving out things that would not compile otherwise. Note that these features might be automatically applied when they depend on toolchains.

Something that needs to be specified via those objects is the dependence on a remote Git repository or local path. This is useful for testing a patched version of a library locally without publishing it to crates.io (https://crates.io/) and having it built by cargo during the parent's build phase:

[dependencies] 
hyper = "*"
rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "0.4" }

Specifying versions with cargo follows a pattern too. Since any crate is encouraged to follow a semantic versioning scheme (<major>.<minor>.<patch>), there are operators that include or exclude certain versions (and thereby APIs). For cargo, those operators are as follows:

  • Tilde (~): Only patch increases are allowed.
  • Caret (^): No major update will be done (2.0.1 to 2.1.0 is OK, to 3.0.1 is not!) .
  • Wildcard (*): Allows any version, but it can be used to replace a position.

These operators avoid future dependency headaches and introduce a stable API without missing the required updates and fixes.

It isn't possible to publish a crate with wildcard dependencies. After all, which version is the target computer supposed to use? This is why cargo enforces explicit version numbers when running cargo publish.

There are several ways to work with purpose-specific dependencies. They can either be declared by platform ([target.wasm32-unknown-unknown]) or by their intention: there is a dependency type, [dev-dependencies], for compiling tests, examples, and benchmarks, but there is also a build-only dependency specification, [build-dependencies], that will be separated from others.

Once the dependencies are specified, they are resolved and looked up to generate a dependency tree within the project. This is where the Cargo.lock file comes in.