В Scala существует Потоковый класс, который очень похож на итератор. Различие в теме между Итератором и Потоком в Scala? предложения некоторое понимание сходств и различий между двумя.
Наблюдение, как использовать поток, довольно просто, но у меня нет очень многих общих примеров использования, где я использовал бы поток вместо других артефактов.
Идеи я имею прямо сейчас:
Поэтому я пропустил какое-либо большое использование? Или действительно ли это - предпочтение разработчика по большей части?
Спасибо
поток
- это ITERATOR
AS ImmyTable.list
состоит в Mutable.List
. При благополучности предотвращается, предотвращает класс ошибок, иногда за счет производительности.
Сама SCALAC не невосприимчит к этим проблемам: http://article.gmane.org/gmane.comp.lang.scala.internals/2831
Как указывает Даниэль, благосклонность лени над строгой Упростите алгоритмы и облегчают их составлять.
В дополнение к ответу Даниэля, имейте в виду, что поток
полезен для короткого замыкания оценки. Например, предположим, что у меня есть огромный набор функций, которые берут string
и возврат параметр [String]
, и я хочу продолжать выполнять их, пока один из них не работает:
val stringOps = List(
(s:String) => if (s.length>10) Some(s.length.toString) else None ,
(s:String) => if (s.length==0) Some("empty") else None ,
(s:String) => if (s.indexOf(" ")>=0) Some(s.trim) else None
);
, Я, конечно, не хочу выполнить список в целом список , и в списке нет никакого удобного метода
, который говорит: «Обработайте это как функции и выполнить их до одного из них Возвращает что-то кроме Нет
». Что делать? Возможно, это:
def transform(input: String, ops: List[String=>Option[String]]) = {
ops.toStream.map( _(input) ).find(_ isDefined).getOrElse(None)
}
Это принимает список и обрабатывает его как поток
(который на самом деле не оценивает ничего), затем определяет новый поток
, который является результатом нанесения Функции (но это еще ничего не оценивает и еще не оценивает), то ищет первый, который определяется - и здесь, волшебно, он оглядывается назад и понимает, что он должен применить карту и получить правильные данные из исходного списка - и затем разворачивать его из опции [Опция [String]]
на опцию [String]
Использование GetOrelse
.
Вот пример:
scala> transform("This is a really long string",stringOps)
res0: Option[String] = Some(28)
scala> transform("",stringOps)
res1: Option[String] = Some(empty)
scala> transform(" hi ",stringOps)
res2: Option[String] = Some(hi)
scala> transform("no-match",stringOps)
res3: Option[String] = None
Но работает ли он? Если мы поставят printLn
в наших функциях в наши функции, чтобы мы могли сказать, будут ли они вызвать, мы получаем
val stringOps = List(
(s:String) => {println("1"); if (s.length>10) Some(s.length.toString) else None },
(s:String) => {println("2"); if (s.length==0) Some("empty") else None },
(s:String) => {println("3"); if (s.indexOf(" ")>=0) Some(s.trim) else None }
);
// (transform is the same)
scala> transform("This is a really long string",stringOps)
1
res0: Option[String] = Some(28)
scala> transform("no-match",stringOps)
1
2
3
res1: Option[String] = None
(это со Scala 2.8; реализация 2.7, к сожалению, 2,7, к сожалению, и обратите внимание Что вы делают накапливаются длинный список , нет
, поскольку ваши сбои накапливаются, но предположительно это недорого по сравнению с вашими истинными вычислениями здесь.)
Установка «DPLL алгоритма пролитного кода» в Google возвращает этот очень приятный исходный файл в качестве первого результата. Это, вероятно, слишком аккуратно и приятно быть врученным как домашнее задание без обширного отсека и возиться.
http://www.msc.mu.edu/~cstruble/Class/COSC159/SPRING2004/Code/dpll.pl
Второй результат - это эта страница вопроса здесь, как так высоко оценивается.
-121--5044731- Основное отличие по потоку
и а также итератором
в том, что последний является смешным и «одним выстрелом», так что говорить, в то время как бывший нет. ITERATOR
имеет лучшую площадь памяти, чем поток
, но тот факт, что он - это Music, может быть неудобным.
Возьмите этот классический генератор Prime Number, например:
def primeStream(s: Stream[Int]): Stream[Int] =
Stream.cons(s.head, primeStream(s.tail filter { _ % s.head != 0 }))
val primes = primeStream(Stream.from(2))
Это может быть легко написано с помощью ITERATOR
, но итератор
не будет Простые числа вычисляются до сих пор.
Итак, один важный аспект потока
состоит в том, что вы можете передать его другим функциям, не будучи дублирован первым, или для получения его снова и снова генерировать его.
Что касается дорогих вычислений / бесконечных списков, эти вещи могут быть выполнены с помощью итератора
. Бесконечные списки на самом деле довольно полезны - вы просто не знаете этого, потому что у вас этого не было, поэтому вы видели алгоритмы, которые являются более сложными, чем строго необходимыми, просто чтобы справиться с насильственными конечными размерами.