Легкий совет для запоминания, для понимания попытается вернуть тип коллекции первого генератора, в данном случае Option [Int].Итак, если вы начнете с Some (1) , вам следует ожидать результата Option [T].
Если вы хотите получить результат типа List , вам следует начать с генератора списков.
Зачем иметь это ограничение и не предполагать, что вы всегда захотите какой-топоследовательность?Может возникнуть ситуация, когда имеет смысл вернуть Option
.Возможно, у вас есть Option[Int]
, который вы хотите объединить с чем-то, чтобы получить Option[List[Int]]
, скажем, с помощью следующей функции: (i:Int) => if (i > 0) List.range(0, i) else None
;тогда вы могли бы написать это и получить None, когда вещи «не имеют смысла»:
val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None
for (i <- Some(5); j <- f(i)) yield j
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4))
for (i <- None; j <- f(i)) yield j
// returns: Option[List[Int]] = None
for (i <- Some(-3); j <- f(i)) yield j
// returns: Option[List[Int]] = None
Как для понимания в общем случае являются на самом деле довольно общим механизмомобъединить объект типа M[T]
с функцией (T) => M[U]
, чтобы получить объект типа M[U]
.В вашем примере M может быть Option или List.В общем, это должен быть тот же тип M
.Таким образом, вы не можете объединить Option с List.Для примеров других вещей, которые могут быть M
, посмотрите на подклассы этой черты .
Почему сочетание List[T]
с (T) => Option[T]
работало, хотя, когда вы начали со Списка?В этом случае библиотека использует более общий тип, где это имеет смысл.Таким образом, вы можете комбинировать List с Traversable, и существует неявное преобразование из Option в Traversable.
Суть в следующем: подумайте, какой тип вы хотите, чтобы выражение возвращало, и начните с этого типа в качестве первого генератора.Оберните его в этот тип, если это необходимо.