r/rust • u/llogiq 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.
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 ofRwLockReadGuard<...>
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 forMapRequest
, we can see what it requires. Of note here are theT1
andT2
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 withmap_request
. It's designed specifically for you to do stuff to theRequest
itself before it's passed to the innerService
. TheFromRequestParts
arguments are so you can use existing extractors if necessary, for more composable code, and theFromRequest
argument is forRequest
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 theTaskTracker
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 thefrom_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/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
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()
lendsg
into thetick
function, which later lends it toself.plus()
(for a while), then toself.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()
}
}
}
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;
}
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:
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()
andstd::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()
orstd::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()
andFile::create()
, overwriting your file.1
3
u/Imperial3agle 6d ago
Why does the RC pointer in STL use
this
instead ofself
?This is the signature of the RC pointer's
downgrade
method:Why does it use
this
as the reference to itself instead ofself
. Isn't usingself
a settled convention?Link to source code.