This is the permalink for the full archive of #Rust tips: https://octodon.social/@rust
`#[deny(warnings)]` will sooner or later break your code.
#Rust keeps adding new warnings and refining behavior of existing ones. If you're not prepared to deal with potential new compilation errors every 6 weeks, don't use #[deny(warnings)].
Rustc has a cap-lints feature to disable this footgun in dependencies, but it doesn't help macro-generated code and top-level crates.
The `.collect()` method on #Rust iterators can construct many different types, and is extensible via FromIterator trait.
Here's the list of supported types in the standard library:
https://doc.rust-lang.org/std/iter/trait.FromIterator.html#implementors
You read it as FromIterator</* type of items in the iterator */> for /* type it makes */
If you want to rush a #Rust function to return quicker, write:
fn foo() -> i32 {
return return return return return !!!!!!!!!!111;
}
https://www.reddit.com/r/rust/comments/g5rsuh/show_me_the_most_illegal_rust_code_youve_ever/fo6onb9/
#Rust borrow checker won't let you call a method that takes &mut self and a reference to something else in the same struct:
self.mutate_item(&self.item) // :(
There are a few workarounds for this:
https://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/
async {} block in #Rustlang behaves like a closure. It does _not_ run any code automatically. It only creates an inactive object, which has to be spawned or awaited to start doing anything.
Example of incorrect usage:
fn main() {
async {
println!("closure");
return;
};
println!("surprise");
}
It prints "surprise", and nothing else!
If you want to create an async stream, the easy solution is a generator macro:
It lets you write the stream as a loop with `yield` instead of implementing traits and managing state manually.
If you're wondering why your #rustlang project is pulling in a certain dependency, you can find out with:
cargo tree -i dependency_name
You can also find duplicate (usually outdated) dependencies with:
cargo tree -d
#Rust constants create a new temporary value every time you mention them.
You can do with whatever you want with the temporary value from a constant, even mutate it. But it only affects each temporary copy, not the constant.
```
use std::cell::Cell;
const C: Cell<bool> = Cell::new(false);
fn main() {
C.set(true);
assert_eq!(false, C.get());
}
```
If your project depends on a Nightly version of the #Rust compiler, you can create `rust-toolchain` file with the required version. It will make Cargo automatically switch to the right compiler for the build.
https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file
If you're defining an alias for your crate's Result type, instead of:
type Result<T> = std::result::Result<T, MyError>;
use:
type Result<T, E = MyError> = std::result::Result<T, E>;
This still works as `Result<()>`, but doesn't cause errors when someone accidentally shadows std's Result with it. It also makes Rustdoc display the error type explicitly in the documentation.
If you have an iterator of `Result`s, you can collect and unwrap all values into a `Vec` on success or return the first `Err` found:
let files_contents = file_names.iter().map(read_file).collect::<Result<Vec<_>, _>>()?;
If you did `.collect::<Vec<_>>()` instead, you'd have an array of mixed `Ok`/`Err` values.
See in #Rust playground: https://is.gd/4GZ45I
If you want to create an async stream, the easy solution is a generator macro:
It lets you write the stream as a loop with `yield` instead of implementing traits and managing state manually.
When you create a #Rustlang function expecting an optional reference, use `Option<&Foo>` rather than `&Option<Foo>`.
fn optional(good: Option<&Foo>, bad: &Option<Foo>) {…}
Both optimize to the same representation, but `Option<&Foo>` is easier to work with, and is more universal, because it can be cheaply created from an owned option with `.as_ref()`.
Does your #rust crate have optional features? Are you sure all combinations of the feature flags work correctly? You can verify this with this cargo plugin: https://lib.rs/cargo-all-features
In #Rust you can cast concrete type to an abstract trait object (e.g. `&i32` as `&dyn Debug`), but you can't (yet) cast a trait object as another trait (e.g. `dyn Error` can't be cast as `dyn Debug`).
The workaround is to add a method to the trait that asks for a different dyn type (e.g. `as_debug(&self) -> &dyn Debug`). That allows trait implementers to cast their concrete type.
This workaround can be automated: https://stackoverflow.com/a/28664881/27009
async {} block in #Rustlang behaves like a closure. It does _not_ run any code automatically. It only creates an inactive object, which has to be spawned or awaited to start doing anything.
Example of incorrect usage:
fn main() {
async {
println!("closure");
return;
};
println!("surprise");
}
It prints "surprise", and nothing else!
Dropping of a #Rust #Future stops its execution. There's also a higher-level wrapper that makes Futures cancellable on demand:
https://docs.rs/futures/0.3.4/futures/future/struct.Abortable.html