I'm storing an Arc<HashMap<String, Thing>>
in a struct impl and want to return an Arc<Thing>
from a method (by doing a lookup) on the HashMap, by reusing the same Arc (because it won't work otherwise) - is that possible?
No. Arc
is a pointer, and it has to know the size of T
. You cannot transmute T
.
Why do you say it won't work otherwise?
Ah, yes, must know the size of the heap data.
I can't construct a new Arc with a wrapped ref without getting into lifetime issues that put me down this path in the first place.
I'll probably just have to have the slightly less ergonomic API of returning Arc<HashMap<String, Thing>> and having clients do the lookup.
Note that this isn't specific to Arc<T>
- if you tried to return it as any owned value at all, this wouldn't work, and for much the same reason.
Rather than borrowing, you might want to think about restructuring the ownership hierarchy of the borrowed data, if that's feasible. If it is, then perhaps you could avoid using Arc<T>
altogether.
Alternately, if Arc<Thing>
is ultimately what you want to be passing around, then you should store Arc<Thing>
as the values in your HashMap.
It's not because the data is held by a struct and I we can't prove that the struct has static lifetime. The data is iniited at startup and last for the life of the program.
Using OnceLock
was suggested here, but would require substantial refactoring.
Box::leak is another possibility and might have been better than what I did.
I do store Arc<Thing>
as the values in the HashMap. That's exactly what it is - the OP shows that.
But since an Arc's value can't change, I couldn't return an Arc<&Thing> without creating a new Arc. And you can't do that without cloning, so then I lose the advantage I was going for all along: not having to clone.
I should give more detail: The data is a map of dates to temporal data. A master cache holds the entire data set - years worth of data - and clients are typically after a few days at a time. So cloning on each get() is very wasteful.
And that's where the code is now, after a 3-hour refactoring to use Arc.
I will have to explore Box::leak, or using OnceLock after all...
Cloning an Arc
increments the refcount. It doesn't clone the pointed data. That's the whole point of Arc
.
Your original post says Arc<HashMap<String, Thing>>
. I am suggesting changing this to HashMap<String, Arc<Thing>>
.
(Or possibly Arc<HashMap<String, Arc<Thing>>>
if you need to share both the entire HashMap and individual values.)

But since an Arc's value can't change, I couldn't return an Arc<&Thing> without creating a new Arc.
The idea is that you would return Arc<Thing>
(not Arc<&Thing>
). You would do this by cloning the Arc
, which just returns a new pointer to the same value. (Arc::clone
doesn’t allocate, or create a new Thing
. It’s just like returning a shared &Thing
pointer, except that it also bumps the reference count. The only thing that gets copied is a pointer.)
Note: To avoid confusion, it would be useful to share some actual (or simplified) code, including what you already tried and why it doesn’t work for you.
You are correct that I've caused confusion by simplifying the example! Apologies to the group.
You also gave me a great idea with the notion of moving the scope of the Arc
s; alas, due to my oversimplification, that doesn't quite work either.
I will now lay out all the relevant details.
Thing
is actually a Vec<DailyHistory>
, and the get accessor requires potentially filtering the contents of that Vec
based on some criteria.
My goal was to be able to return a new Vec
without having to clone the DailyHistory
s.
So, to be clear (now), the data structure is HashMap<NaiveDate, Vec<DailyHistory>>
.
Also, although using Box::leak would work, in the long-term, I don't really want to leak. Now, the program needs to be restarted daily to fetch new daily data, but, in the long-term, ideally, it would re-init for a new day, dropping the old data. (Therefore static is also not ideal.)

You also gave me a great idea with the notion of moving the scope of the
Arc
s; alas, due to my oversimplification, that doesn't quite work either.

Thing
is actually aVec<DailyHistory>
, and the get accessor requires potentially filtering the contents of thatVec
based on some criteria.My goal was to be able to return a new
Vec
without having to clone theDailyHistory
s.So, to be clear (now), the data structure is
HashMap<NaiveDate, Vec<DailyHistory>>
.
You can keep moving the Arc
inward as far as you want. If you make your data structure a HashMap<NaiveDate, Vec<Arc<DailyHistory>>>
, then you can still just clone the Arc
s after filtering.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.