Сворачивание с помощью массива строк

#string #vector #rust #fold

#строка #вектор #Ржавчина #сгиб

Вопрос:

Я попробовал некоторый код, подобный этому:

 fn main() {
   let a = vec!["May", "June"];
   let s = a.iter().fold("", |s2, s3|
      s2   s3
   );
   println!("{}", s == "MayJune");
}
  

Результат:

 error[E0369]: cannot add `amp;amp;str` to `amp;str`
 --> a.rs:4:10
  |
4 |       s2   s3
  |       -- ^ -- amp;amp;str
  |       |  |
  |       |  ` ` cannot be used to concatenate two `amp;str` strings
  |       amp;str
  |
help: `to_owned()` can be used to create an owned `String` from a string
reference. String concatenation appends the string on the right to the string
on the left and may require reallocation. This requires ownership of the string
on the left
  |
4 |       s2.to_owned()   s3
  |       ^^^^^^^^^^^^^
  

Хорошо, достаточно справедливо. Поэтому я меняю свой код именно на это. Но тогда я получаю это:

 error[E0308]: mismatched types
 --> a.rs:4:7
  |
4 |       s2.to_owned()   s3
  |       ^^^^^^^^^^^^^^^^^^
  |       |
  |       expected `amp;str`, found struct `std::string::String`
  |       help: consider borrowing here: `amp;(s2.to_owned()   s3)`
  

Хорошо, достаточно справедливо. Поэтому я меняю свой код именно на это. Но тогда я получаю это:

 error[E0515]: cannot return reference to temporary value
 --> a.rs:4:7
  |
4 |       amp;(s2.to_owned()   s3)
  |       ^--------------------
  |       ||
  |       |temporary value created here
  |       returns a reference to data owned by the current function
  

Почему Rust выдает ложное предложение, и возможно ли то, что я пытаюсь сделать? Обратите внимание, я бы предпочел избегать таких предложений, как «просто использовать join » или аналогичных, поскольку этот вопрос предназначен для решения более общей проблемы. Версия Rust:

 rustc 1.46.0 (04488afe3 2020-08-24)
  

Комментарии:

1. play.rust-lang.org/…

2. «Почему Rust выдает ложное предложение, и возможно ли то, что я пытаюсь сделать?» ну, компилятор — это не человек, с точки зрения компилятора закрытие должно возвращать amp; str, потому что вы вводите в него начальное значение типа amp; str. Ошибка имеет смысл

3. В качестве альтернативы вы могли бы использовать format!("{}{}", s2, s3) для объединения строк

Ответ №1:

возможно ли то, что я пытаюсь сделать?

Stargazeur предоставил рабочую версию в своем комментарии: начальное значение / накопитель должно быть String , а не amp;str .

Почему Rust выдает ложное предложение

Rustc не обладает достаточно глобальным видением, чтобы он мог видеть проблему «детали», но он не понимает, что это действительно локальный эффект более крупной проблемы: подпись сгиба

 fn fold<B, F>(self, init: B, f: F) -> B 
  

поскольку вы предоставляете fold an amp;str , оно должно в конечном итоге возвращать amp;str , что возможно только в том случае, F если просто возвращает что-то, что оно получает «извне», а не если оно создает что-либо внутри. Поскольку вы хотите создать что-то внутри вашего обратного вызова, значение init является проблемой.

Однако Rustc не видит конфликта на этом уровне, потому что, насколько это касается, это совершенно правильная подпись, например, вы можете следовать цепочке вещей через hashmap, возвращая постоянную ссылку на строку для всего, что его волнует, единственный реальный конфликт, который он видит, находится между этим:

  F: FnMut(B, Self::Item) -> B
  

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

  • Rust не позволяет добавлять два amp;str вместе, потому что это неявно выделяло бы String , что является своего рода скрытой проблемой, которую основная команда предпочла бы не скрывать, поэтому <a rel="noreferrer noopener nofollow" href="https://doc.rust-lang.org/std/ops/trait.Add.html#impl-Add» rel=»nofollow noreferrer»> Add реализуется только между String и amp;str , это первая проблема, которую вы видите, и поскольку это несколько необычно (средний язык просто позволяет вам объединять строковые элементы или даже не-вообще-строки в строки), разработчики rustc добавили текст справки, в котором отмечается, что LHS должен принадлежать String , что обычно помогает / работает, но
  • затем добавление возвращает String , так что теперь ваша функция больше не соответствует F подписи: поскольку инициализация является amp;str типом накопителя, вам нужно вернуть amp;str
  • за исключением того, что если вы попытаетесь создать ссылку на строку, которую вы только что создали, вы только что создали ее внутри функции, как только функция вернет строку, она будет мертвой, а ссылка останется висячей, чего rust не может допустить

И вот так, несмотря на лучшие намерения, поскольку представление компилятора слишком локально, оно бесхитростно ведет вас по совершенно бесполезному пути разочарования.

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