Замыкания в мнопоточном приложении

Здравствуйте!
Есть такой код

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;
    }
}

Rust отказывается компилировать, т.к. “the parameter type C may not live long enough” и “the parameter type T may not live long enough”. Подробнее можно посмотреть в песочнице.
Но как так? Они передаются во владение замыкания и там уже живут сколько нужно. Тем более, что T вообще в замыкании напрямую не используется, к тому же, обёрнуто в 2 контейнера, которые регулируют доступ!

И попутный вопрос - зачем Rust потребовал ограничений на T: Send + Sync? К этому же типу нет непосредственного доступа из разных потоков, только через обёртки.

Они передаются во владение замыкания и там уже живут сколько нужно.

И там уже живут до тех пор, пока замыкание не завершится, причём компилятор понятия не имеет, когда это произойдёт. Чтобы гарантировать возможность этого, компилятор должен быть уверен, что никакое внешнее событие не может их испортить - например, что они не содержат ссылок на что-нибудь, что основной поток может освободить раньше, чем новый поток перестанет ими пользоваться. А это и есть 'static.

И попутный вопрос - зачем Rust потребовал ограничений на T: Send + Sync? К этому же типу нет непосредственного доступа из разных потоков, только через обёртки.

Send нужен для любого доступа из других потоков, невзирая на то, есть ли там обёртки. Что касается Sync, то RwLock не запрещает двум потокам одновременно получить доступ на чтение и за счёт interior mutability что-нибудь в типе T сломать.

Но ведь там передача владения! Это ж эксклюзивный доступ вообще, никаких ссылок там быть не может - это не позволят сделать проверки компилятора вызывающего кода.

Вообще вот такой работает.
Но получается, что 'static - это не синоним глобальной переменной, а больше синоним “владения”? Хотя это, вроде-бы, и из декларации понятно…

Но ведь там передача владения! Это ж эксклюзивный доступ вообще, никаких ссылок там быть не может - это не позволят сделать проверки компилятора вызывающего кода.

Вовсе нет. Тип T вполне мог бы быть ссылкой &str, позаимствованной откуда-то.

Но получается, что 'static - это не синоним глобальной переменной, а больше синоним “владения”? Хотя это, вроде-бы, и из декларации понятно…

Верно. 'static обозначает, что тип с этим свойством может жить до конца программы. Это может быть владение (тип без лайфтаймов вообще), это могут быть ссылки &'static в код программы, это может быть динамически выделенная память, про которую с помощью Box::leak мы гарантируем, что она не будет освобождена до завершения программы. Вообще лайфтаймы у типов – это не “сколько живёт переменная такая-то”, а “каково максимальное разрешённое время жизни переменных этого типа”.

2 лайка