Каковы лучшие практики при создании анонимной переменной со статическим временем жизни?

Это вопрос, состоящий из двух частей: (1) Является ли хорошей практикой передавать статические ссылки на функции высшего порядка, чтобы они (параметры) жили достаточно долго? (2) Как лучше всего создать анонимную переменную со статическим временем жизни?

Вот контекст: у меня есть метафункция, которая возвращает закрытие на основе своих параметров. Чтобы параметры существовали достаточно долго, они должны быть статическими ссылками. Например.,

pub enum Uncloneable { Variant }

pub fn get_getter(param:&'static Uncloneable)
                  -> Box<dyn Fn() -> &'static Uncloneable> {
    Box::new(move || { param })
}

Но я не хочу загромождать свой код множеством const определений каждый раз, когда я вызываю get_getter, например

fn main() {
    let _result = get_getter({
        const VAR:Uncloneable = Uncloneable::Variant;
        &VAR
    });
}

Мое текущее решение - использовать макрос:

#[macro_export]
macro_rules! staticify {
    ($type:tt :: $variant:tt) => {{
        const VAR:$type = $type::$variant;
        &VAR
    }};
}

fn main() {
    let _result = get_getter(staticify!(Uncloneable::Variant));
}

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

Вот полный код на Rust Playground.


person trexinf14s    schedule 09.04.2020    source источник
comment
Вы понимаете, что вам все это не нужно, или ваш реальный вариант использования более сложен? get_getter(&Uncloneable::Variant) как раз подходит для этого примера.   -  person mcarton    schedule 09.04.2020
comment
Оказалось, что я неверно истолковал ошибку компилятора, из-за чего я подумал, что все это было необходимо. Спасибо, что указали на очень глупую ошибку!   -  person trexinf14s    schedule 09.04.2020
comment
Кстати, в соответствии с C-GETTER В соответствии с рекомендациями API, более условным названием функции get_getter будет просто getter.   -  person E_net4 the curator    schedule 09.04.2020


Ответы (1)


Я не думаю, что ваш макрос является антипаттерном, но в данном случае он не обязательно очень полезен. const не выделяет никакого хранилища для значения, он просто выполняет подстановку во время компиляции, поэтому ваш код такой же, как и просто:

fn main() {
    let _result = get_getter(&Uncloneable::Variant);
}

Другими словами, нет необходимости использовать const для хранения значения.

Кроме того, ссылка автоматически повышается до &'static Uncloneable. В справочнике по Rust объясняется:

При использовании выражения значения в большинстве контекстов выражения места создается временная безымянная ячейка памяти, инициализированная этим значением, и вместо этого выражение оценивается в это место, за исключением случаев, когда повышается до 'static. Продвижение выражения значения в слот 'static происходит, когда выражение может быть записано в виде константы, заимствовано и разыменовано в том заимствовании, в котором выражение было изначально записано, без изменения поведения во время выполнения. То есть Продвинутое выражение может быть оценено во время компиляции, и результирующее значение не содержит внутренней изменчивости или деструкторов (эти свойства определяются на основе значения, где это возможно, например, &None всегда имеет тип &'static Option<_>, поскольку он не содержит ничего запрещенного).

По сути, если вы можете использовать константу, такую ​​как ваш код, вы также можете просто взять ссылку на это значение напрямую, и она будет автоматически повышена до ссылки 'static, если это возможно.

person Frxstrem    schedule 09.04.2020
comment
Оказалось, что я неверно истолковал ошибку компилятора, из-за чего я подумал, что все это было необходимо. Спасибо за любезное указание на очень глупую ошибку и за весь контекст! - person trexinf14s; 09.04.2020