Невозможно использовать format_args!из-за временного значения освобождается в конце этого утверждения - PullRequest
2 голосов
/ 25 мая 2019

Я пытаюсь создать свой собственный LogRecord и передать его в log ящик.

use log::RecordBuilder;

fn main() {
    let msg = format_args!("Completed: {}, Elapsed={:?}", "blah", 20);
    //let msg = format_args!("This is OK");
    let mut builder = RecordBuilder::new();
    let _log_rec = builder
        .args(msg)
        .build();
}

У меня временная проблема с вызовом метода args . Ошибка

 --> src/main.rs:4:28
  |
4 |     let msg = format_args!("Completed: {}, Elapsed={:?}", "blah", 20);
  |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             - temporary value is freed at the end of this statement
  |                            |
  |                            creates a temporary which is freed while still in use
...
8 |         .args(msg)
  |               --- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

Обычно это было бы легко исправить - просто поместите временную переменную в локальную переменную. В этом случае, однако, я не понимаю, как это исправить, так как у меня уже есть все, что я могу придумать, в локальные переменные (и поэтому я не думаю, что этот вопрос является дубликатом других). Кажется, это что-то особенное для макроса format_args!.

Интересно, что проблема исчезнет, ​​если вы не используете {} заполнителей при вызове format_args!().

Фактическое решение

Решение от E_net4 верное. Это не сработало сразу в моем реальном коде, который был:

impl Drop for ExecutionTimer2 {
    fn drop(&mut self) {
        let elapsed = self.start_time.elapsed();

        let mut builder = RecordBuilder::new();
        let log_rec = builder
            .level(Level::Debug)
            .target("ExecutionTimer")
            .file(Some(self.file))
            .module_path(Some(self.module_path))
            .line(Some(self.line))
            .args(format_args!("Completed: {}, Elapsed={:?}", self.name, elapsed))
            .build();

        let logger = log::logger();
        logger.log(&log_rec);
    }
}

но я снова применил метод 'inlining', чтобы придумать этот код, который компилируется:

impl Drop for ExecutionTimer2 {
    fn drop(&mut self) {
        let elapsed = self.start_time.elapsed();
        let mut builder = RecordBuilder::new();
        let logger = log::logger();

        logger.log(&
            builder
                .level(Level::Debug)
                .target("ExecutionTimer")
                .file(Some(self.file))
                .module_path(Some(self.module_path))
                .line(Some(self.line))
                .args(format_args!("Completed: {}, Elapsed={:?}", self.name, elapsed))
                .build()
        );
    }
}

1 Ответ

2 голосов
Ожидается, что

format_args! будет вызван именно там, где будет использоваться возвращаемое значение.

let mut builder = RecordBuilder::new();
let _log_rec = builder
    .args(format_args!("Completed: {}, Elapsed={:?}", "blah", 20))
    .build();

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...