Foo::new(words).split_first()
будет интерпретироваться примерно как
let tmp = Foo::new(words);
let ret = tmp.split_first();
drop(tmp);
ret
Если бы Rust позволил вам сделать это, ссылки в ret
указали бы s> [править: разрешено типом split_first
указывать *] на теперь упавшее значение tmp
. Так что хорошо, что Руст запрещает это. Если бы вы написали эквивалентную однострочную версию в C ++, вы бы молча получили неопределенное поведение.
Написав let
привязку самостоятельно, вы задерживаете отбрасывание до конца области действия, расширяя тем самым область, где эти ссылки безопасны.
Подробнее см. временные времена жизни в справочнике по ржавчине.
* Редактировать: Как указал Jmb , реальная проблема в этом конкретном примере заключается в том, что тип
fn split_first(&'a self) -> &'a str
недостаточно конкретен, и лучшим решением является уточните тип до:
fn split_first<'b>(&'b self) -> &'a str
, что может быть сокращено:
fn split_first(&self) -> &'a str
Это передает предполагаемую гарантию того, что возвращаемые ссылки не указывают на Foo<'a>
(только на строку сам по себе).
Править: На основе Вашего обновления ошибка может быть связана с перечислением в Вашем классе объекта. См. эту запись в блоге для получения дополнительной информации и обходное решение. Я оставляю свой исходный ответ как улучшение на Вашем синтаксисе запроса.
Попытайтесь делать выбор первого объекта в самом запросе с помощью FirstOrDefault и затем проверьте, является ли результат пустым.
int compareCategory = (int)pCategory; // just a guess
var result = (from r in entities.MachineRevision
where r.Machine.IdMachine == pIdMachine
&& r.Category == compareCategory
select r).FirstOrDefault();
if (result != null)
{
return new oMachineRevision(result.IdMachineRevision);
}
Почему не только используют FirstOrDefault () и проверяют на пустой указатель? Я не вижу преимущества в запросах для количества и затем взятии первого элемента.
В стандартной реализации linq операторы "выбирают" и "где" карта к методам, которые возвращают IEnumerable или IQueryable. Столь стандартные linq методы при использовании должны всегда возвращать IEnumerable из запроса ни один объект.
Но методы linq, которые являются кандидатами на linq операторы, не ограничиваются методами, возвращая IEnumerables, любой метод, возвращая что-либо может быть выбран.
В случае, если у Вас есть методы экземпляра под названием "Выбор" и "Где" тот возврат отдельный объект или методы расширений, которые характерны для Вашего класса и возвращают отдельный объект, они будут использоваться вместо стандарта linq.
Мое предположение - то, что или "Выбор" или "Где" метод, определенный в Вашем классе, заставляет linq возвратить единственное значение вместо a IEnumerable<T>
.
Я не знал, что различные анонимные объекты будут созданы в зависимости от результата запроса. Я предполагаю, что они просто хотели, чтобы результаты имели тип IEnumerable
Как насчет того, чтобы использовать foreach?
var results = from r in entities.MachineRevision
where r.Machine.IdMachine == pIdMachine
&& r.Category == pCategory
select r;
foreach( var r in results )
{
yield return new oMachineRevision( r.IdMachineRevision );
}
попытайтесь использовать
IENumerable<MachineRevision> results = from r in entities.MachineRevision
...
вместо этого.
Я думаю, что это - var, это вызывает Вашу проблему.
Править:
Прочитайте сообщение об ошибке. "Не удалось создать постоянную стоимость типа 'Тип закрытия'. Только типы примитивов ('такие как Int32, Строка и Гуид') поддерживаются в этом контексте".
Одно из этих сравнений с типом, который не является интервалом, строкой или гуидом. Я предполагаю Категорию.
r.Machine.IdMachine == pIdMachine && r.Category == pCategory
Интересно, LinqToSql позволит эту конструкцию. Не знайте, почему LinqToEntities не поддерживает это.
Думаю, вы также можете выбрать нужный элемент другим, более простым способом, используя лямбда-выражения.
var result = entities.MachineRevision
.Where(x => x.Machine.IdMachine == pIdMachine)
.Where(y => y.Category == (int)pCategory)
.FirstOrDefault();
if (result != null)
{
return new oMachineRevision(result.IdMachineRevision);
}
, а затем действуя как обычно