Могу ли я принять два & str параметра и вернуть один или другой? - PullRequest
2 голосов
/ 06 марта 2020

Итак, я попытался сделать эту функцию:

pub fn pluralize(singular: &str, plural: &str, count: u64) -> &str {
    if count == 1 {
        singular
    } else {
        plural
    }
}

Но я получил пожизненную ошибку:

error[E0106]: missing lifetime specifier
   --> test.rs:165:63
    |
165 | pub fn pluralize(singular: &str, plural: &str, count: u64) -> &str {
    |                                                               ^ expected lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `singular` or `plural`

Я могу заставить его скомпилировать и работать, возвращая String вместо & str и вызывая to_string () для каждого входа. Но это менее эффективно, поэтому я хотел бы знать, есть ли хороший / idomati c способ сделать это так, как я задумал.

1 Ответ

1 голос
/ 06 марта 2020

Вы можете сказать Rust, что результат жив, только если аргументы singular и plural живы:

fn pluralize<'a>(singular: &'a str, plural: &'a str, count: u64) -> &'a str {
    // ...
}

Обратите внимание, что это мешает вам сделать что-то вроде этого:

let singular = "one".to_string();
let pluralized = {
    let plural = "two".to_string();
    pluralize(&singular, &plural, 1)
};
println!("{:?}", pluralized);

То есть, хотя pluralized будет ссылкой на singular, который живет достаточно долго, чтобы быть напечатанным в конце, Руст предполагает, что это также может быть ссылкой на plural, что выходит за рамки до окончательного утверждения печати. Таким образом, компилятор говорит вам:

error[E0597]: `plural` does not live long enough
  --> test.rs:9:30
   |
7  |     let pluralized = {
   |         ---------- borrow later stored here
8  |         let plural = "two".to_string();
9  |         pluralize(&singular, &plural, 1)
   |                              ^^^^^^^ borrowed value does not live long enough
10 |     };
   |     - `plural` dropped here while still borrowed

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

fn do_nothing<'a>(s: &'a str) -> &'a str { ... }

Это означает, что do_nothing - это функция, которая принимает аргумент с временем жизни 'a и возвращает ссылку с тем же временем жизни 'a. Но компилятор реализует некоторые разумные правила, чтобы угадать время жизни типа результата в большинстве распространенных случаев. Это позволяет вам пропустить время жизни для аргументов и типов результатов, например:

fn do_nothing(s: &str) -> &str { ... }

Правила таковы:

  • Каждое допустимое время жизни в параметрах становится отдельным параметр времени жизни.
  • Если в параметрах используется ровно одно время жизни (исключенное или нет), то время жизни назначается всем временам жизни разрешенного выхода.
  • Если у получателя тип & Self или & mut Self затем время жизни этой ссылки на Self назначается всем параметрам времени жизни элидируемого выхода.

(от https://doc.rust-lang.org/stable/reference/lifetime-elision.html)

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

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