2015-04-21 2 views
10

У меня возникли проблемы с попыткой понять, почему я не могу вернуть значение &str, полученное от String (доброта, когда будет готова as_str?), И я делаю что-то неправильно. Я получаю эту идею, потому что ничто из того, что я делаю, не заставляет ценность жить достаточно долго, чтобы ее использовать.Почему я не могу вернуть значение & str, генерируемое из строки?

Я пытаюсь реализовать error::Error для настраиваемого структуры:

impl error::Error for LexicalError { 
    fn description(&self) -> &str { 
     let s = format!("{}", self); 

     // s doesn't live long enough to do this, I've tried 
     // cloning s and using that, but still the clone doesn't 
     // live long enough. 
     s.trim() 
    } 

    fn cause(&self) -> Option<&error::Error> { 
     None 
    } 
} 

(для полного фрагмента кода, вот playpen)

Я не могу понять, как вернуть & ул от description, я хотел бы повторно использовать логику Display, если, конечно, я полностью не понимаю, что должно возвращаться description (возможно, краткое описание проблемы). Либо я получаю ту же проблему с возвратом format!(...), которая является переменной, которую я, похоже, не может прожить достаточно долго, чтобы быть полезной для меня.

+3

'описание' должно быть описание ошибки, не вдаваясь в детали; 'fmt :: Display' должен быть там, чтобы увеличить его с подробной информацией по желанию. –

+0

@ChrisMorgan Я иду из Go как самый последний язык, с которым я играл, и я ошибочно предположил, что метод описания аналогичен методу Go's Error. Спасибо за информацию! –

ответ

12

Во-первых, давайте посмотрим, что на самом деле ожидается. Существует неявная жизнь в подписи description:

fn description(&self) -> &str 
// Can be rewritten as 
fn description<'a>(&'a self) -> &'a str 

Возвращаемый указатель должен быть действителен в течение по крайней мере до тех пор, как self. Теперь рассмотрим s. Он будет содержать String, принадлежащую строке, и он выходит за пределы области действия в конце функции. Было бы неверно возвращать &s, потому что s не работает, когда функция возвращается. trim возвращает фрагмент строки, который занимает s, но срез снова действителен только до тех пор, пока s есть.

Вам нужно вернуть срез строки, который переживает вызов метода, поэтому это исключает что-либо в стеке. Если бы вы были свободны выбирать тип возврата, решением было бы переместить строку из функции. Для этого потребуется строка, принадлежащая государству, а затем возвращаемый тип будет String, а не &str. К сожалению, вы не можете свободно выбирать тип возврата здесь.

Чтобы вернуть строку кусок, который переживет вызов метода, я вижу два варианта:

  1. Использование ломтика &'static строки. Это, безусловно, переживет вызов, но требует, чтобы строка была известна во время компиляции. Строковые литералы имеют тип &'static str. Это подходящий вариант, если описание не содержит динамических данных.

  2. Хранить принадлежащую строку в LexicalError. Это гарантирует, что вы можете вернуть указатель на него, который действителен для всего срока службы self. Вы можете добавить поле desc: String в LexicalError и выполнить форматирование при построении ошибки. Тогда метод будет реализован как

    fn description(&self) -> &str { 
        &self.desc 
    } 
    

    Для повторного использования, вы можете сделать Display написать ту же строку.

Согласно documentation of Error, Display могут быть использованы для получения дополнительных деталей.Если вы хотите включить динамические данные в ошибку, то Display - отличное место для его форматирования, но вы можете опустить его для description. Это позволит использовать первый подход.

+0

Я думаю, что второй вариант подойдет мне лучше всего. Что заставляет меня задавать вопрос, связанный с полузависимостью, - это «String» и «& str» взаимозаменяемы? Или, я полагаю, 'String' и' str' в этом случае, другие мудрые вы бы возвращали заимствованные '& str'. У меня плохое понимание точной разницы между «String» и «& str» иначе, чем когда они происходят (например, я знаю тип строковых литералов и при построении строк более сложных, чем простое форматирование, я использую 'String') и когда (слегка) выбирать между ними. –

+0

Они не взаимозаменяемы. У 'String' есть свои байты UTF-8, тогда как' & str' просто указывает на байты UTF-8, заимствованные где-то. 'String' и' & str' аналогичны 'Vec ' и '& [T]'. Вы можете взять 'String' для получения' & str'. В этом случае заимствованный фрагмент не может пережить владение 'String'. Существует [глава о строках в книге] (http://doc.rust-lang.org/1.0.0-beta.2/book/strings.html), которая может быть полезна. – Ruud

+0

Я прошел через книгу, что вы сказали, имеет больше смысла, чем то, что я помню. Возможно, я просто не получил достаточного понимания языка, чтобы понять этот раздел. Спасибо за информацию, это была большая помощь. –

Смежные вопросы