2014-12-03 5 views
4

У меня есть перечисление ржавчины, которое я хочу использовать, однако я получаю ошибку;Явная ошибка времени жизни в ржавчине

error: explicit lifetime bound required 
numeric(Num), 
     ~~~ 

Перечисление в вопросе:

enum expr{ 
    numeric(Num), 
    symbol(String), 
} 

Я не думаю, что я понимаю, что заимствуются здесь. Мое намерение состояло в том, чтобы Num или String имели такое же время жизни, что и содержащее выражение, позволяющее мне возвращать их из функций.

ответ

8

Сообщение об ошибке несколько вводит в заблуждение. Num - это признак, и он является типом динамического размера, поэтому вы не можете иметь его значения без какой-либо косвенности (ссылка или Box). Причина этого проста; просто задайте себе вопрос: какой размер (в байтах) expr значения перечисления должны иметь? Это, конечно, не менее String, но как насчет Num? Произвольные типы могут реализовать эту черту, поэтому для того, чтобы быть здоровым, expr должен иметь бесконечный размер!

Следовательно, вы можете использовать черты как типы только с каким-либо указателем: &Num или Box<Num>. Указатели всегда имеют фиксированный размер, а объекты признаков - «жирные» указатели, сохраняя в них дополнительную информацию, чтобы помочь при диспетчеризации метода.

Также признаки обычно используются в качестве границ для параметров типового типа. Поскольку generics monomorphized, они превращаются в статические типы в скомпилированном коде, поэтому их размер всегда статически известен, и им не нужны указатели. Использование дженериков должно быть по умолчанию, и вы должны переключиться на объекты объектов только тогда, когда знаете, почему дженерики не будут работать для вас.

Это возможные варианты определения вашего типа. С дженериков:

enum Expr<N: Num> { 
    Numeric(N), 
    Symbol(String) 
} 

Тре объекта через ссылку:

enum Expr<'a> { // ' 
    Numeric(&'a Num + 'a), 
    Symbol(String) 
} 

Черта объекта с коробкой:

enum Expr { 
    Numeric(Box<Num + 'static>), // ' // I used 'static because numbers usually don't contain references inside them 
    Symbol(String) 
} 

Вы можете прочитать больше о дженериков и черт в the official guide, хотя в момент не содержит информации о объектах признаков. Пожалуйста, спросите, не понимаете ли вы что-то.

Обновление

'a в

enum Expr<'a> { // ' 
    Numeric(&'a Num + 'a), 
    Symbol(String) 
} 

является параметром времени жизни. Он определяет как время жизни ссылки, так и внутренних объектов объекта внутри Numeric. &'a Num + 'a - это тип, который вы можете прочитать как «объект-признак за ссылкой, который живет как минимум до 'a со ссылками внутри него, которые также живут как минимум до 'a». То есть, во-первых, вы указываете 'a в качестве эталонного ресурса: &'a, и, во-вторых, вы определяете срок службы внутренних объектов объектов: Num + 'a. Последнее необходимо, потому что черты могут быть реализованы для любых типов, включая те, которые содержат ссылки внутри них, поэтому вам нужно также установить минимальное время жизни этих ссылок в тип объекта-объекта, в противном случае проверка перевода не будет корректно работать с объектами признаков.

С Box ситуация очень похожа. Box<Num + 'static> - это «объект-признак внутри выделенного кучи окна со ссылками внутри него, которые живут как минимум до тех пор, пока 'static». Тип Box - это интеллектуальный указатель на принадлежащие кучу данные. Поскольку он владеет данными, которые он хранит, ему не нужен параметр времени жизни, например, ссылки. Однако объект-признак все еще может содержать ссылки внутри него, поэтому Num + 'a по-прежнему используется; Я просто решил использовать время жизни 'static вместо добавления другого параметра времени жизни. Это связано с тем, что числовые типы обычно просты и не содержат ссылок внутри них, и это эквивалентно 'static. Конечно, вы можете добавить параметр продолжительности жизни, если хотите.

Обратите внимание, что все эти варианты являются правильными:

&'a SomeTrait + 'a 
&'a SomeTrait + 'static 
Box<SomeTrait + 'a> // ' 
Box<SomeTrait + 'static> 

Даже это правильно, с 'a и 'b как различных параметров жизни:

&'a SomeTrait + 'b 

хотя это редко используется, потому что 'b должен быть как минимум до 'a (в противном случае внутренности объекта-объекта могут быть недействительными, пока он сам по-прежнему жив), поэтому вы можете просто использовать &'a SomeTrait + 'a.

+0

Общая версия неудобна для использования, поскольку создание символа 'Symbol' может привести к тому, что компилятор не сможет вывести конкретный тип для' N'. Более того, если в конечном итоге 'Expr' эволюционирует, чтобы содержать варианты, содержащие подвыражения, общая версия не будет масштабироваться. Я согласен с тем, что в общем случае общую версию следует рассматривать первыми, но в этой ситуации я считаю, что это неправильное решение. Кроме того, в зависимости от требований может быть достаточно заменить «Numeric (N)» двумя вариантами: «Integer (i64)» и «Float (f64)», чтобы избежать бокса. –

+0

Спасибо, что это было действительно полезно. У меня есть вопрос, хотя добавление 'a в числовом (& 'a Num +' a) и добавление' static в Numeric (Box ) делает , – ragingSloth

+0

@ragingSloth, я обновил свой ответ. –

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