LINUX.ORG.RU

Rust - расскажите мне как работает 'static

 


1

3

Объясните пожалуйста что такое лайфтайм ’static. Не очень понимаю как он работает. Исходя из документации, это верхней лайтайм в программе. Но при этом во многих приписках указывает что это просто наибольший возможный лайфтайм. Пример:

pub struct Future<V: Send + 'static, E: Send + Clone + 'static> {
    value: Option<Result<V, E>>,
    next: Option<Box<FnMut(&Result<V, E>) -> () + Send>>
}

Если исходить из первого утверждения, то V никогда не должно дропнуться и навсегда остаться в живых, но все же это случается тогда, когда дропается сам объект Future. Исходя их этого вопрос - а что же тогда обозначает ’static? Привязка ко времени жизни самого верхнего объекта?


Могу предположить, что это связано с замыканиями, время жизни типа которых короче, чем 'static, но мне самому интересно, какой правильный ответ.

dave ★★★★★
()

static - гарантирует, что ссылка на объект просуществует всё время работы программы. То есть это ссылки на глобальные константы, функции и тп.

RazrFalcon ★★★★★
()
Ответ на: комментарий от vertexua

Вот верхушка:

fn main() {

    {
        let mut p: CompletablePromise<Foo, TSafe<Fail + Send>> = CompletablePromise::new();
        let mut fut = p.future();

        fut.map(|v| {
            println!("Map");
            Ok(format!("{}", v.value))
        }).on_complete(|v| {
            if v.is_ok() {
                println!("Final result = {}", v.as_ref().ok().unwrap());
            } else {
                println!("Error = {}", v.as_ref().err().unwrap().lock().unwrap());
            }
        });


        thread::spawn(move || {
            p.success(Foo { value: 1000 });
        });
    }

    thread::sleep_ms(10000000);
}

TSafe это алиас к Arc<Mutex>. У Foo объявлен Drop с печатью теста Dropped!. Вот что я получу в выводе:

Map
Final result = 1000
Dropped!

p.success(Foo { value: 1000 }) это граница времени жизни объекта p, который содержит ссылку на fut. Вот в этом месте и происходит дроп Foo со всеми остальными объектами.

Serbis
() автор топика
Ответ на: комментарий от RazrFalcon

Да, вот почитал тоже. По сути это гарантия что вот он обьект, у него самого нету ссылок на то, что может помереть. Мы ним владеем, можем дропать смело когда хотим. Но вопрос не в этом, а в том, что сам обьект не ссылается на то, что может помереть в любой момент

vertexua ★★★★★
()
Ответ на: комментарий от Serbis

Так всё верно. Если у вас объект владеет своим содержимым - то он подпадает под определение 'static.

А вы чего хотите добиться?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Ну я как бы это и хотел получить и крайне удивился что оно работает именно так. Просто в документации получается очень мутно описано что такое static. Получается что у каждого объекта есть свой собственный static и V 'static это можно расшифровать так Future<V...(V: 'пока жив объект Fututre ...

Serbis
() автор топика
Ответ на: комментарий от Serbis

у каждого объекта есть свой собственный static

Я не силён в деталях реализации, но лайфтаймы распространяются только на ссылки, насколько я знаю.

В вашем обобщенном коде, в вашем конкретном случае, 'static вообще должен быть бесполезным.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Ну теперь понятно, там есть места из-за которых без них не получается скопилить:

    pub fn map<S>(&mut self, mut f: Box<FnMut(&V) -> Result<S, E> + Send>) -> WrappedFuture<S, E>
        where S: Send + Clone + 'static
    {
        let mut p: CompletablePromise<S, E> = CompletablePromise::new();
        let fut = p.future();
        self.next = Some(Box::new( move |v: &Result<V, E>| {
            if v.is_ok() {
                let x = v.as_ref().ok().unwrap();
                let result = f(x);
                p.complete(result);
            } else {
                let err = v.as_ref().err().unwrap().clone();
                let result: Result<S, E> = Err(err);
                p.complete(result);
            }
        }));

        if self.value.is_some() {
            if let Some(ref mut v) = self.value {
                if let Some(ref mut f) = self.next {
                    f(v)
                }
            }
        }

        fut
    }

И там получается что в self.next = Some(Box::new( move |v: &Result<V, E>| { кладется во внутрь замыкание, в котором происходит ссылка на V. И компилятор без static на это сообщает что V потенциально на тот момент уже может сдохнуть так как не определено его время жизни относительно Future.

Serbis
() автор топика
Ответ на: комментарий от Serbis

Честно говоря я с таким кодом не сталкиваюсь. У меня всё намного проще. Но могу предположить использовать Copy или Sized?, чтобы намекнуть компилятору, что это точно не ссылка.

RazrFalcon ★★★★★
()
Ответ на: комментарий от anonymous

Оффтопик

/ / /

Вот этим меня жутко раздражает Rust, ему на каждое А, нужно объяснять что это буква, русского алфавита, заглавная, черного цвета. Иначе получишь от компилятора что А не может быть обернута в объект потому что неизвестно что именно это за А и вообще неизвестно буква ли это. А что про си, сомневаюсь я что там будет меньше мусора. Самый добрый язык в плане чистоты имхо это TypeScript, там эта же функция очевиднее в миллион раз.

    map<S>(f: (T) => S): Future<S> {
        let p = new CompletablePromise<S>();
        this.next = (v) => {
            if (v.isSuccess()) {
                let result = Try.doWork(() => f(v.get()));
                p.complete(result);
            } else {
                p.complete(v as Try<any> as Try<S>);
            }

        };

        return p.future;
    }
Serbis
() автор топика
Ответ на: комментарий от Serbis

[code] if self.value.is_some() {[/code]

if self.value.is_some() можно убрать. И выше вместе v.is_ok() лучше использовать паттерн матчинг. И кода меньше (unwrap не нужен) и статических гарантий больше.

provaton ★★★★★
()
Последнее исправление: provaton (всего исправлений: 1)
Ответ на: комментарий от Serbis

Иначе получишь от компилятора что А не может быть обернута в объект потому что неизвестно что именно это за А и вообще неизвестно буква ли это.

Точно так же и в ТС, за тем исключением, что у тебя есть any. А так же в ТС есть какой-никакой вывод типов из контекста, а тут вообще ничего нет.

А что про си, сомневаюсь я что там будет меньше мусора.

Чини методичку.

anonymous
()
Ответ на: комментарий от Serbis

В TypeScript сборщик мусора, там всякие лайфтаймы побоку. Rust решает другую задачу

vertexua ★★★★★
()
Ответ на: комментарий от anonymous

Вот такие штуки как в этом треде - это как если бы в плюсах внутри iostream ковырялись бы. Такой пургой никто не страдает реально. Лайфтаймы для тугих перцев, которые хотят какую-то магию нагородить с клубком указателей на друг-друга, чтобы все было бесплатно, полный zero-cost и чтобы компилятор доказал что это корркетно.

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 2)

Не очень понимаю как он работает.

Оно никак не работает. Это хинты чекеру(который ничего не может), которые ничего не значат. С внешнего уровня ты можешь засунуть туда что угодно. Смотри на то, что туда передаётся.

anonymous
()
Ответ на: комментарий от vertexua

Вот такие штуки как в этом треде - это как если бы в плюсах внутри iostream ковырялись бы.

Ты не лозунги кида, а что-нибудь осмысленное.

Лайфтаймы для тугих перцев, которые хотят какую-то магию нагородить с клубком указателей на друг-друга, чтобы все было бесплатно, полный zero-cost и чтобы компилятор доказал что это корркетно.

Опять лозунги. Тема никакого отношения к лайтаймам не имеем и они не являются zero-cost, да и компилятор ничего не может доказать.

anonymous
()
Ответ на: комментарий от vertexua

Вот такие штуки как в этом треде - это как если бы в плюсах внутри iostream ковырялись бы

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

Serbis
() автор топика
Ответ на: комментарий от Serbis

Использовать ограничение 'static для полиморфного типа, особенно монады - обычная практика для Rust. Здесь просто компилятор должен быть уверен, что твой тип V будет жить в течение всего времени жизни программы. В 99% случаев так оно и происходит.

Как насчет замыканий? Не проверял мою версию? Сможешь ли создать свое вычисление не на основе статического типа, и именно, скормив туда замыкание? С трудом представляю такой случай, ну, а вдруг?

dave ★★★★★
()

в rust шаблонные параметры, в том числе и лайфтаймы, относятся к определению типа. T: 'static означает, что тип T должен существовать все время выполнения программы. Не сама переменная, а именно тип.

Очевидно, что для типов, у которых все поля - либо значения, либо статические ссылки, это условие выполняется. А для всех остальных - не выполняется. Все очень просто.

Чтобы сделать статической саму переменную, а не ее тип, нужно объявить ее с ключевым словом static вместо let.

anonymous
()

Объект типажа может содержать ссылки. Лайфтайм 'static указывает, что эти ссылки живут не меньше, чем программа.

quantum-troll ★★★★★
()
Ответ на: комментарий от anonymous

Это хинты чекеру(который ничего не может), которые ничего не значат.

У вас с ним много общего. Ты тоже ничего не можешь и твоё мнение ничего не значит xD

anonymous
()
Ответ на: комментарий от quantum-troll

Типы не существуют во время выполнения.

имеется ввиду, например, что тип &'a i8 прекращает существование, когда заканчивается лайфтайм 'a

понятно, что типов в рантайме нет, но дешаблонизированный тип T<'a> имеет смысл только в скоупе 'a

MyTrooName ★★★★★
()
Ответ на: комментарий от anonymous

в принципе да. а 0 - это костыль в системе с натуральными числами.

MyTrooName ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.