Rust tips is a user on octodon.social. You can follow them or interact with them if you have an account anywhere in the fediverse. If you don't, you can sign up here.

Rust tips @rust@octodon.social

If you want to see assembly output to check how optimizes a function, you can use rust.godbolt.org/

Rust tips boosted

PSA: is an unpleasant place. It's better to ask questions on users.rust-lang.org where you will get a good answer, even if you ask a "duplicate" question about lifetimes, like every Rust user does.

The convenient way to use C libraries in is via "sys" crates.

Here's a comprehensive guide to making sys crates: kornel.ski/rust-sys-crate

Rust tips boosted

I think I'll try to collect any blog posts I find with insight and clues to good #Rust programming with the hashtag #RustWisdom

This is the first such collected blog post: jwilm.io/blog/from-str-to-cow/

If you need to find'n'replace expressions in code, use github.com/google/rerast

For example, you can replace all uses of the old `try!()` macro with the `?` operator that replaced it:

users.rust-lang.org/t/automati

Cargo build scripts (build.rs) need special care to support cross-compilation correctly.

Don't use `#[cfg(target…)]`/`cfg!(target=…)`, because all macros and constants in the source code are for the machine that does the compilation, which may be different from the architecture the code is cross-compiled for (e.g. macOS can build libraries for Android).

Instead, check values of `std::env::var("TARGET")`, `CARGO_CFG_TARGET_ARCH`, etc.

kazlauskas.me/entries/writing-

Open documentation for your project and its dependencies:

cargo doc --open

Or for a specific dependency only:

cargo doc -p crate_name --open

And for itself:

rustup docs

It all works offline.

Get automated improvement suggestions for your code from Clippy:

cargo +nightly install --force clippy

cargo clippy # run in your project directory

If some suggestions are too nitpicky for you, you can hide them by adding `allow(<clippy warning name>)` to your code:

#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

Clippy depends on Rust compiler version, so you'll need to install it again after every update.

iterators are evaluated lazily, so they don't do anything until they're used to produce a value (e.g. `next()`, `collect()`, `count()` or `for i in iter {}`)

There's no "for_each()" method to just run an iterator without getting values out of it. Use `for _ in iter {}` instead.

When implementing a custom iterator you may be tempted to reuse the same buffer for each element for efficiency. Unfortunately, that won't compile, because the `Iterator` trait allows such usage:

let one = iter.next();
let two = iter.next();

If you could return iterator's internal buffer, then `one`'s content would be overwritten when `two` is created.

Use `StreamingIterator` instead: github.com/sfackler/streaming-

won't let you cut the branch you're sitting on.

Sometimes you need to change a complex struct or enum based on its contents. However, you can't do this inside a `match` that takes references, because the references inside the `match` keep a "lock" on the whole object and prevent it from being replaced.

The solution is to use `match` only to check the condition, and perform replacement in a separate step after the `match`.

It's better explained with code:

play.rust-lang.org/?gist=f7616

Rust tips boosted

debug print format `{:?}` prints the whole expression in one line.

There's a pretty-print `{:#?}` which prints structs and vectors in a nice multi-line indented format.

println!("{:#?}", complex_value);

If you're implementing Debug trait for your types manually, check out Formatter methods to support pretty-printing:

doc.rust-lang.org/std/fmt/stru

In functions returning `Result` you can avoid repeating `Ok()` all the time by moving it to the outermost scope.

Instead of:

match foo {
bar => Ok(1)
baz => Ok(2)
quz => Ok(3)
_ => Err("etc"),
}

use:

Ok(match foo {
bar => 1,
baz => 2,
quz => 3,
_ => Err("etc")?,
})

uses types to automatically manage memory.

The owned `String` type tells the compiler to free it.
The borrowed `&str` tells the compiler NOT to free it.

But you can't mix them, because the compiler won't know whether to free the variable or not:

let label = if x != 0 {x.to_string()} else {"zero"};

The tip:

let tmp;
let label = if x != 0 {tmp = x.to_string(); &tmp} else {"zero"};

Now the compiler knows to free the `tmp`, but not the `label`.

Cow: is.gd/vi8eMF

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 playground: is.gd/4GZ45I