Подтвердить что ты не робот

Println! error: аргумент format должен быть строковым литералом

Эта чрезвычайно простая программа Rust:

fn main() {
    let c = "hello";
    println!(c);

}

выдает следующую ошибку времени компиляции:

main.rs:15:14: 15:15 error: format argument must be a string literal.
main.rs:15     println!(c);
                        ^
note: in expansion of format_args!
<std macros>:2:54: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
main.rs:15:5: 15:17 note: expansion site
error: aborting due to previous error
Could not compile `numrust`.

Замена программы:

fn main() {
    println!("Hello");

}

Прекрасно работает.

Значение этой ошибки для меня непонятно, и поиск Google на самом деле не проливает свет на него. Почему передача c в макрос println! вызывает ошибку времени компиляции? Это кажется довольно необычным поведением.

4b9b3361

Ответ 1

Причина, по которой

fn main() {
    let c = "hello";
    println!(c);
}

Невозможно работать, потому что макрос println! смотрит на строку во время компиляции и проверяет соответствие аргументов и аргументов по количеству и типу (это очень хорошо!). В этот момент времени, во время макрооценки, невозможно сказать, что c пришел из литерала или функции или что у вас есть.

Вот пример того, что макрос расширяется:

let c = "hello";
match (&c,) {
    (__arg0,) => {
        #[inline]
        #[allow(dead_code)]
        static __STATIC_FMTSTR: &'static [&'static str] = &[""];
        ::std::io::stdio::println_args(&::std::fmt::Arguments::new(
            __STATIC_FMTSTR,
            &[::std::fmt::argument(::std::fmt::Show::fmt, __arg0)]
        ))
    }
};

Из моего комментария к этому ответу:

Я не думаю, что для компилятора это вообще невозможно понять, но это, вероятно, потребует большой работы (потенциально для небольшого выигрыша). Макросы работают на участках АСТ, которые, как я предполагаю, имеют только информацию о типе. Чтобы работать в этом случае, AST должен был бы включить источник идентификатора и достаточную информацию, чтобы определить его "безопасным". Кроме того, он может плохо взаимодействовать с типом вывода - вы бы хотели знать тип до его выбора!

Из моего комментария к другому ответу:

Сообщение об ошибке запрашивает "строковый литерал". Там fooobar.com/questions/94991/... вопрос о том, что это означает, который ссылается на запись в Википедии:

литерал является обозначением для представления фиксированного значения в исходном коде

"foo" - строковый литерал, 8 - числовой литерал. let s = "foo" - это оператор, который присваивает значение строкового литерала идентификатору (переменной). println!(s) - это оператор, который предоставляет идентификатор макроса.

Ответ 2

Это должно работать:

fn main() {
  let c = "hello";
  println!("{}", c);
}

Строка "{}" - это шаблон, где {} будет заменен следующим аргументом, переданным в println!.

Ответ 3

Если вы действительно хотите определить первый аргумент println! в одном месте я нашел способ сделать это. Вы можете использовать макрос:

macro_rules! hello {() => ("hello")};
println!(hello!());

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

macro_rules! cell_format {() => ("{:<10}")};  // Pads with spaces on right
                                              // to fill up 10 characters
println!(cell_format!(), "Foo");
println!(cell_format!(), 456);

Макрос спас меня от необходимости дублировать опцию форматирования в моем коде.

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

Ответ 4

Если ваша строка формата будет повторно использоваться только умеренное количество раз, и только некоторые переменные данные будут изменены, то небольшая функция может быть лучшим вариантом, чем макрос:

fn pr(x){
    println!("Some stuff that will always repeat, something variable: {}",x);
};

pr("I am the variable data".to_string());

Выходы

Некоторые вещи, которые всегда будут повторяться, что-то переменное: Я - переменные данные