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

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

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

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

 error: expected a literal --> src/main.rs:3:14 | 3 | println!(c); | ^ 

В предыдущих версиях Rust ошибка:

 error: format argument must be a string literal. println!(c); ^ 

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

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

Работает отлично.

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

TL; DR Если вам все равно, почему и просто хотите исправить это, обратитесь к ответу на сестры .


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

 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 должен будет указать источник идентификатора и достаточную информацию, чтобы определить, что он «безопасен». Кроме того, он может плохо взаимодействовать с типом вывода – вы бы хотели знать тип до его выбора!

Сообщение об ошибке запрашивает «строковый литерал». Есть вопрос о том, что это значит, что связано с входом в Википедию :

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

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

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

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

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

Если вы действительно хотите определить первый аргумент 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); 

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

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

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

 fn pr(x: &str) { println!("Some stuff that will always repeat, something variable: {}", x); } pr("I am the variable data"); 

Выходы

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

  • Можно ли управлять размером массива с помощью параметра типа общего?
  • Что означает «несоответствующие типы: ожидаемые» () `» при использовании выражения if?
  • «Задолженность недолговечна», похоже, виноват в неправильной
  • Каков тип возврата операции индексирования?
  • Каков де-факто способ чтения и записи файлов в Rust 1.x?
  • Рекурсивные структуры данных в ржавчине
  • Передача изменчивой самостоятельной ссылки на метод принадлежащего ему объекта
  • Как остановить итерацию и вернуть ошибку, когда Iterator :: map возвращает результат: Err?
  • Могу ли я делать интроспекцию типа с объектами признаков, а затем опускать ее?
  • Есть ли способ создать псевдоним типа для нескольких признаков?
  • Как избежать дублирования функций доступа для изменяемых и неизменных ссылок в Rust?
  • Давайте будем гением компьютера.