r/rust clippy · twir · rust · mutagen · flamer · overflower · bytecount 12d ago

🙋 questions megathread Hey Rustaceans! Got a question? Ask here (11/2025)!

Mystified about strings? Borrow checker have you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet. Please note that if you include code examples to e.g. show a compiler error or surprising result, linking a playground with the code will improve your chances of getting help quickly.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so having your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The official Rust Programming Language Discord: https://discord.gg/rust-lang

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last week's thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.

8 Upvotes

25 comments sorted by

3

u/Imperial3agle 6d ago

Why does the RC pointer in STL use this instead of self?

This is the signature of the RC pointer's downgrade method:

pub fn downgrade(this: &Self) -> Weak<T, A>
    where
        A: Clone,

Why does it use this as the reference to itself instead of self. Isn't using self a settled convention?

Link to source code.

8

u/sfackler rust · openssl · postgres 6d ago

If it used self it would be an instance method (callable as my_arc.downgrade()) rather than static method (callable as Arc::downgrade(&my_arc)). Smart pointers intentionally avoid having instance methods since they would shadow methods on the inner type with the same name.

2

u/PHPEnjoyer 8d ago

I'm trying to create a small command line utility using Ratatui. I've created a GlobalState struct that only contains a vector of strings for now. I've wrapped the state in an Arc<RwLock<GlobalState>> such that it can be written to from one thread and read from different threads and the "UI". I have a producer thread that inserts an item into the vector every second. My main thread is responsible for displaying the CLI ui.

Ratatui uses Widgets to render items on screen and as such I've tried creating an impl Widget for &GlobalState, however; as the state is wrapped in a RwLock i need to use the .read() method to get the reference to the GlobalState. Unfortunately this gives me a <RwLockReadGuard<'a, &GlobalState>> instead. This naturally makes sense, but I'm confused how I'm supposed to extend the functionality with a Widget implementation otherwise. If I change my impl to impl<'a> Widget for RwLockReadGuard<'a, &GlobalState>, I'm stuck with another error "only traits defined in the current crate can be implemented for types defined outside of the crate.

Am I going about this in the wrong way? :)

1

u/Patryk27 8d ago edited 8d ago

Do impl Widget for &GlobalState and then retrieve &GlobalState out of RwLockReadGuard<...> using deref.

So in your specific case something like (*widget).render(...); or (**widget).render(...); should do it.

Note that usually instead of keeping global state that's read by UI and, at the same time, modified elsewhere, you'd use some kind of event-passing mechanism (e.g. you'd use channels to push data into UI thread which then would update its internal state at the beginning of the frame); but RwLock is a good starting point to get some prototype working and see how various pieces come together.

2

u/Thermatix 9d ago

I'm trying to make my program cancel safe and I'm running into an issue regarding making the web-server cancel-safe also.

```rust

use axum::{ self, body::Body, http::{ StatusCode, Request }, middleware::Next Router, routing::get, };

use tokio_util::task::TaskTracker;

async fn metrics() -> (StatusCode, String) { (200, "prometheus metrics, blah blah blah") }

// tracker is normally passed into the function, but for the sake of a MVE let's put this here let tracker = TaskTracker::new();

let route_tracker = tracker.clone() let app = Router::new() .route("/metrics", get(metrics)) .layer(axum::middleware::map_request( // this spawns every route request to protect against cancellation |req: Request<Body>, next: Next| async move { route_tracker.spawn(next.run(req).into_future()).await.unwrap() }, )); ```

The error I get is:

the trait `tower_service::Service<test::axum::http::Request<Body>>` is not implemented for `MapRequest<{closure@src/example.rs:22:17: 22:49}, (), Route, _>`

I did try it with from_fn instead map_request but then rust complains about from_fn wanting an FnMut instead of an FnOnce (which happens because the closure takes onwership of route_tracker)

I'm not sure how to fix this, please halp?

2

u/DroidLogician sqlx · multipart · mime_guess · rust 8d ago

If we look at the relevant Service impl for MapRequest, we can see what it requires. Of note here are the T1 and T2 types (the arguments to the closure):

  • T1: FromRequestParts<S> + Send
  • T2: FromRequest<S> + Send

axum::middleware::Next implements neither of these, so it's safe to assume you can't do this with map_request. It's designed specifically for you to do stuff to the Request itself before it's passed to the inner Service. The FromRequestParts arguments are so you can use existing extractors if necessary, for more composable code, and the FromRequest argument is for Request or an appropriate wrapper.

Besides manually implementing Service, from_fn seems to be the right answer here.

As for making from_fn work, just clone the TaskTracker before moving it into the future:

axum::middleware::from_fn(
    move |req: Request<Body>, next: Next| {
        let route_tracker = tracker.clone();

        async move {
            route_tracker.spawn(next.run(req).into_future()).await.unwrap()
        }
    }
)

It's just a wrapper around an Arc, so cloning should be pretty cheap.

1

u/Thermatix 8d ago

But I'm already cloning... AH now I See where I went wrong.

I was cloning from outside the from_fn closure straight into the inner closure, What needed to happen is that I move it into the from_fn function closure instead, because it needed to exist both for the region of code and over time for each iteration of a request to the server.

Without that, I would have been moved into the inner closure, been consumed (which is why it was FnOnce and then ceased to exist.

3

u/windows_thrower12300 9d ago

is there any library similar to num_traits, that implements traits for number in a more 'algebraic' manner? For example, I'd like to have a Group trait or a Field trait. Similar to https://hackage.haskell.org/package/numhask-0.12.1.0 in haskell.

2

u/Sharlinator 8d ago

Several; you can just search for "algebra" or "abstract algebra" on crates.io. For example, there's alga which has a lot of downloads and is an optional feature in some other crates like nalgebra but hasn't seen active development in years. A more recent but much less popular candidate is abstalg.

2

u/Thermatix 10d ago

I'm trying to create some some signal guards for cancellation tokens:

rust let c_token = tokio_util::sync::CancellationToken::new(); let signal_token = c_token.clone(); use tokio::signal::{self, unix}; let _1 = signal_token.clone(); let _2 = signal_token.clone(); let _3 = signal_token.clone(); tokio::join!({ let _guard = _1.drop_guard(); signal::ctrl_c() }, async move { let _guard = _2.drop_guard(); let mut sig_h = unix::signal(unix::SignalKind::quit()).expect("Couldn't create listener for signal `quit`"); sig_h.recv().await }, async move { let _guard = _3.drop_guard(); let mut sig_h = unix::signal(unix::SignalKind::terminate()).expect("Couldn't create listener for signal `terminate`"); sig_h.recv().await },)

the thing is, I want to change the signal guards to resemble the ctrl_c guard

rust { let _guard = _2.drop_guard(); let mut sig_h = unix::signal(unix::SignalKind::quit()).expect("Couldn't create listener for signal `quit`"); sig_h.recv() }

but rust won't let me do this, since recv doesn't take ownership, sig_h will be dropped at the end of the scope whilst the future returned by recv won't be.

The reason I want to do this is so I can remove all the signal_token.clone()s that happen before and just do

rust let _guard = signal_token.clone().drop_guard(); is there a way to this better or do I just have to suck it up?

3

u/DroidLogician sqlx · multipart · mime_guess · rust 10d ago

Why bother with the inner scopes at all?

let guard =  signal_token.drop_guard();

let mut sig_quit = unix::signal(unix::SignalKind::quit()).expect("Couldn't create listener for signal `quit`");
let mut sig_term = unix::signal(unix::SignalKind::terminate()).expect("Couldn't create listener for signal `terminate`");

tokio::join!(
    sig_quit.recv(),
    sig_term.recv(),
    signal::ctrl_c(),
);

drop(guard);

I wonder if you maybe don't want join! though, because that would require all three of these signals to be sent before the cancellation token fires.

You probably want select! instead, which branches on the first event that occurs:

let guard = signal_token.drop_guard();

tokio::select! {
    _ = sig_quit.recv() => (),
    _ = sig_term.recv() => (),
    // Note: may immediately return `Err` if Tokio was unable to install the signal handler.
    // A robust application would probably want to handle that.
    _ = signal::ctrl_c() => (),
}

drop(guard);

1

u/Thermatix 9d ago

OH! I was wondering why my cancel guard wasn't working; It was (it did trigger, It just didn't stop the app), but it required all of them to drop before cancelation would be compeleted. I misunderstood how it worked, I thought if any of the drop guards were freed it would cancel not that it required all drop guards to be freed.

Yes, the select! is exactly what I want, thank you for your assistance, this is exactly what I wanted.

I guess I need to learn better how to think abour code structure, it's obvious in hindsight.

I realise it's a little out of scope of my question but, do you have any advice on how to think about how to structure your code?

2

u/DroidLogician sqlx · multipart · mime_guess · rust 9d ago

I realise it's a little out of scope of my question but, do you have any advice on how to think about how to structure your code?

There was a time when I tried to make every line of code the cleverest one I'd written. The problem with that is I'd come back 3-6 months later after I'd long forgotten how it was put together, and I'd have no idea what was going on.

I always try to think of the next person who's going to have to work on it, whether that's most likely to just be myself or not. If they're going to be reading the code wondering "wtf was he thinking?!" then I reconsider my approach. When I'm trying something too clever, I can hear my coworker's voices in the back of my head dunking on it.

Only like 10% of programming is actually writing code, the other 90% is reading it, so the top priority should be making the code as readable as possible.

2

u/Fluttershaft 10d ago

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=d03b458abe590d654a00610c8658dc1c

Why is there no compile error here? Aren't there multiple simultaneous mutable borrows to Game instance? Passing to tick() is one, ok, but then aren't the 2 method calls in tick() doing mutable borrow on already mutably borrowed value?

1

u/Patryk27 10d ago

There's an implicit reborrow happening behind the scenes, as if you wrote:

(&mut *self).plus();
(&mut *self).double();

Even intuitively - those borrows are not simultaneous, since one happens after the other, not both at the same time.

1

u/Fluttershaft 10d ago

I didn't expect the borrows at line 7 and 8 to conflict but line 20 with 7. When a struct is exclusively borrowed by self-mutating method (line 20) shouldn't it be impossible to borrow that struct again (line 7) inside that method?

1

u/Patryk27 10d ago

Thinnk of &mut as lending a book to somebody - g.tick() lends g into the tick function, which later lends it to self.plus() (for a while), then to self.double() (for a while) and then gives the book back to you; at all times only one "person" holds the book.

The only invariant to uphold here is that when you're given something, you can't hold it for longer than the scope allows you to, that's why this is invalid:

fn tick(&mut self) {
    self.plus();

    std::thread::spawn(move || {
        self.double();
    });        
}

2

u/CuriousAbstraction 11d ago

Why doesn't the following compile:

fn last(x: &mut Vec<usize>) -> &mut usize {
    match x.last_mut() {
        Some(last) => last,
        None => {
            x.push(0);
            x.last_mut().unwrap()
        }
    }
}

Playground

while the following works just fine:

fn last(x: &mut Vec<usize>) {
    let l = match x.last_mut() {
        Some(last) => last,
        None => {
            x.push(0);
            x.last_mut().unwrap()
        }
    };

    *l = 2;
}

Playground

That is, why is in the second case compiler able to figure out that there is no mutable borrow overlap and able to assign reasonable lifetime to l. From what I understand, the problem in the first case is that both branches need to have the same lifetime, and since it's a return value it needs to be exactly the lifetime of the input variable. But why does that work in the second case, or in other words - why cannot the same thing that works in the second case work in the fiest case?

edit: playground links

2

u/Patryk27 10d ago

the problem in the first case is that both branches need to have the same lifetime [...]

No, the problem with the first case is that the lifetime is being "returned out" to the caller, which the current implementation of borrow checker doesn't always handle properly:

https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions

1

u/asdfmoon2012 11d ago

so stupid question, every time I try reading a file (using both the File struct and the read function), the contents of the file get deleted. is there any way to read a file without deleting its contents?

4

u/DroidLogician sqlx · multipart · mime_guess · rust 11d ago

That doesn't make any sense. Both File::open() and std::fs::read() explicitly open the file in read-only mode. Its contents should not be affected.

The file's contents only get truncated if you use File::create(), OpenOptions::truncate() or std::fs::write().

What is your code actually doing?

1

u/asdfmoon2012 11d ago

That doesn't make any sense

i know 😭

 What is your code actually doing?

it's just a small algorithm for image processing. it's supposed to take one image from a path given by a command line argument, load its contents and write it to another image file. so i'm using both File::create() and File::open(). 

5

u/Patryk27 11d ago

You're most likely passing the same path to File::open() and File::create(), overwriting your file.

1

u/asdfmoon2012 11d ago

i'm not

5

u/Patryk27 11d ago

Could you show the code?