pub struct A<T> {
list: Arc<RwLock<HashMap<u32, T>>>,
}
impl<T: Send + Sync> A<T> {
fn new<C: Fn(T) + Send + Sync>(cleaner: C) -> Self {
let list = Arc::new(RwLock::new(HashMap::new()));
let res = Self {
list: list.clone(),
};
spawn(move || {
let c = cleaner;
let l = list;
});
return res;
}
}
and it's doesn't compile because of "the parameter type C may not live long enough" and "the parameter type T may not live long enough". You can try to compile in playground.
Why is it??? All this variables, clean and list move to closure! And T even not use directly, only contains in HashMap!
One more question - why rust wants T had Send + Sync boundaries? It's wrapped by RwLock which process any inter-threads access.
Generic types are allowed to be temporary references, e.g. the C callback could be borrowing a variable on stack, which would be unsafe to use from another thread.
To solve this, forbid these types from containing temporary references. This is done by adding 'static requirement:
I wrote this code right now. It looks like work. It was compile at least.
But I don't understand why should I use 'static lifetime. Not T neither C doesn't live so long!
Lifetimes apply only to borrows, not to owned objects (without inner references), e.g. i32 doesn't have a lifetime, &i32 has. Owned objects without any temporary references inside meet any lifetime requirement, because their lifetime is not limited to any scope.
You would own it only if it was an owned type, but T can be anything. It could be &str. Owning a type doesn't mean the type is thread-safe, for example you can own Cow<'a, str> wrapper, but it contains a temporary reference.
Another way to see T: 'static is that Tcan live an arbitrarily long time, because it's not borrowing anything else that would limit it. So that owned T is passed to the new thread, and the thread is allowed to keep that value as long as it wants. Whereas something like a T = &'a str can only live at most through the 'a lifetime.