From 717dd5be1869018bd5676109729859f5657e2e26 Mon Sep 17 00:00:00 2001 From: evgeny-rybnikov Date: Wed, 12 Jul 2023 15:17:51 +0300 Subject: [PATCH] grammar corrections --- _ru/overviews/collections-2.13/arrays.md | 9 ++++----- .../concrete-immutable-collection-classes.md | 10 +++++----- .../concrete-mutable-collection-classes.md | 6 +++--- .../creating-collections-from-scratch.md | 2 +- _ru/overviews/collections-2.13/equality.md | 2 +- _ru/overviews/collections-2.13/iterators.md | 8 ++++---- _ru/overviews/collections-2.13/overview.md | 2 +- .../collections-2.13/performance-characteristics.md | 2 +- _ru/overviews/collections-2.13/seqs.md | 2 +- _ru/overviews/collections-2.13/sets.md | 4 ++-- _ru/overviews/collections-2.13/strings.md | 2 +- _ru/overviews/collections-2.13/trait-iterable.md | 2 +- _ru/overviews/collections-2.13/views.md | 4 ++-- 13 files changed, 27 insertions(+), 28 deletions(-) diff --git a/_ru/overviews/collections-2.13/arrays.md b/_ru/overviews/collections-2.13/arrays.md index dba3fb4e08..856c08002c 100644 --- a/_ru/overviews/collections-2.13/arrays.md +++ b/_ru/overviews/collections-2.13/arrays.md @@ -10,8 +10,7 @@ language: ru --- [Массивы](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) особый вид коллекций в Scala. -С одной стороны, Scala массивы соответствуют массивам из Java. Например, Scala массив `Array[Int]` реализован в виде Java `int[]`, а `Array[Double]` как Java `double[]` и `Array[String]` как Java `String[]` - С другой стороны, Scala массивы дают намного больше чем их Java аналоги. Во-первых Scala массивы могут быть обобщены (_generic_). То есть вы можете описать массив как `Array[T]`, где `T` дополнительный `параметр-тип` массива или же абстрактный тип. +С одной стороны, Scala массивы соответствуют массивам из Java. Например, Scala массив `Array[Int]` реализован в виде Java `int[]`, а `Array[Double]` как Java `double[]` и `Array[String]` как Java `String[]`. С другой стороны, Scala массивы дают намного больше чем их Java аналоги. Во-первых, Scala массивы могут быть обобщены (_generic_). То есть вы можете описать массив как `Array[T]`, где `T` дополнительный `параметр-тип` массива или же абстрактный тип. Во-вторых, Scala массивы совместимы со списками (`Seq`) Scala - вы можете передавать `Array[T]` на вход туда, где требуется `Seq[T]`. Ну и наконец, Scala массивы также поддерживают все операции, которые есть у списков. Вот пример: scala> val a1 = Array(1, 2, 3) @@ -23,7 +22,7 @@ language: ru scala> a3.reverse res0: Array[Int] = Array(9, 3) -Учитывая то что Scala массивы соответствуют массивам из Java, каким же образом реализованы остальные дополнительные возможности массивов в Scala? +Учитывая то, что Scala массивы соответствуют массивам из Java, каким же образом реализованы остальные дополнительные возможности массивов в Scala? Реализация массивов в Scala постоянно использует неявные преобразования. В Scala массив не пытается _притворяться_ последовательностью. Он и не может, потому что тип данных лежащий в основе массива не является подтипом `Seq`. Вместо этого, используя "упаковывание", происходит неявное преобразование между массивами и экземплярами класса `scala.collection.mutable.ArraySeq`, который является подклассом `Seq`. Вот как это работает: scala> val seq: collection.Seq[Int] = a1 @@ -50,7 +49,7 @@ language: ru Вы видите, что вызов `reverse` на `seq`, который является `ArraySeq`, даст снова `ArraySeq`. Это логично, потому что массивы - это `Seqs`, и вызов `reverse` на любом `Seq` даст снова `Seq`. С другой стороны, вызов `reverse` на экземпляре класса `ArrayOps` даст значение `Array`, а не `Seq`. -Пример `ArrayOps`, приведенный выше искусственный и используется лишь, чтоб показать разницу с `ArraySeq`. Обычно, вы никогда не создаете экземпляры класса `ArrayOps`. Вы просто вызываете методы `Seq` на массиве: +Пример `ArrayOps`, приведенный выше искусственный и используется лишь, чтобы показать разницу с `ArraySeq`. Обычно, вы никогда не создаете экземпляры класса `ArrayOps`. Вы просто вызываете методы `Seq` на массиве: scala> a1.reverse res4: Array[Int] = Array(3, 2, 1) @@ -62,7 +61,7 @@ language: ru где `intArrayOps` - неявное преобразование, которое было вставлено ранее. В связи с этим возникает вопрос, как компилятор выбрал `intArrayOps` вместо другого неявного преобразования в `ArraySeq` в строке выше. В конце концов, оба преобразования преобразуют массив в тип, поддерживающий метод reverse. Ответ на этот вопрос заключается в том, что два неявных преобразования имеют приоритет. Преобразование `ArrayOps` имеет больший приоритет, чем преобразование `ArraySeq`. Первый определяется в объекте `Predef`, а второй - в классе `scala.LowPriorityImplicits`, который `Predef` наследует. Неявные преобразования в дочерних классах и дочерних объектах имеют более высокий приоритет над преобразованиями в базовых классах. Таким образом, если оба преобразования применимы, выбирается вариант в `Predef`. Очень похожая схема используется для строк. -Итак, теперь вы знаете, как массивы могут быть совместимы с последовательностями и как они могут поддерживать все операции последовательностей. А как же обобщения? В Java нельзя написать `T[]`, где `T` является параметром типа. Как же представлен Scala `Array[T]`? На самом деле обобщенный массив типа `Array[T]` может быть любым из восьми примитивных типов массивов Java `byte[]`, `short[]`, `char[]`, `int[] `, `long[] `, `float[]`, `double ` или может быть массивом объектов. Единственным общим типом, включающим все эти типы, является `AnyRef` (или, равнозначно `java.lang.Object`), так что это тот тип в который компилятор Scala отобразит `Array[T]`. Во время исполнения, при обращении к элементу массива типа `Array[T]`, происходит последовательность проверок типов, которые определяют тип массива, за которыми следует подходящая операция на Java-массиве. Эти проверки типов замедляют работу массивов. Можно ожидать падения скорости доступа к обобщенным массивам в три-четыре раза, по сравнению с обычными массивами или массивами объектов. Это означает, что если вам нужна максимальная производительность, вам следует выбирать конкретные массивы, вместо обобщенных. Отображать обобщенный массив еще пол беды, нам нужен еще способ создания обобщенных массивов. Это куда более сложная задача, которая требует, от вас, небольшой помощи. Чтобы проиллюстрировать проблему, рассмотрим следующую попытку написания обобщенного метода, который создает массив. +Итак, теперь вы знаете, как массивы могут быть совместимы с последовательностями и как они могут поддерживать все операции последовательностей. А как же обобщения? В Java нельзя написать `T[]`, где `T` является параметром типа. Как же представлен Scala `Array[T]`? На самом деле обобщенный массив типа `Array[T]` может быть любым из восьми примитивных типов массивов Java `byte[]`, `short[]`, `char[]`, `int[] `, `long[] `, `float[]`, `double ` или может быть массивом объектов. Единственным общим типом, включающим все эти типы, является `AnyRef` (или, равнозначно `java.lang.Object`), так что это тот тип, в который компилятор Scala отобразит `Array[T]`. Во время исполнения, при обращении к элементу массива типа `Array[T]`, происходит последовательность проверок типов, которые определяют тип массива, за которыми следует подходящая операция на Java-массиве. Эти проверки типов замедляют работу массивов. Можно ожидать падения скорости доступа к обобщенным массивам в три-четыре раза, по сравнению с обычными массивами или массивами объектов. Это означает, что если вам нужна максимальная производительность, вам следует выбирать конкретные массивы, вместо обобщенных. Отображать обобщенный массив еще полбеды, нам нужен еще способ создания обобщенных массивов. Это куда более сложная задача, которая требует от вас небольшой помощи. Чтобы проиллюстрировать проблему, рассмотрим следующую попытку написания обобщенного метода, который создает массив. // это неправильно! def evenElems[T](xs: Vector[T]): Array[T] = { diff --git a/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md b/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md index dd9f2e5658..e2f94e3455 100644 --- a/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md +++ b/_ru/overviews/collections-2.13/concrete-immutable-collection-classes.md @@ -24,7 +24,7 @@ Scala предлагает множество конечных реализац scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty lazyList: scala.collection.immutable.LazyList[Int] = LazyList(?) -На первом месте в этом ленивом списке - 1, а на втором - 2 и 3. Но ни один из элементов здесь не выводится, потому что список еще не вычислен! Ленивые списки задуманны обрабатываться лениво, поэтому метод `toString`, не выводит всех элементов, не заставляя производить дополнительные вычисления. +На первом месте в этом ленивом списке - 1, а на втором - 2 и 3. Но ни один из элементов здесь не выводится, потому что список еще не вычислен! Ленивые списки задуманы обрабатываться лениво, поэтому метод `toString` не выводит всех элементов, не заставляя производить дополнительные вычисления. Ниже приводится более сложный пример. Вычисления ленивого списка, содержащего последовательность Фибоначчи, которая начинается с заданных двух чисел. Последовательность Фибоначчи - это последовательность, в которой каждый элемент представляет собой сумму двух предыдущих элементов в серии. @@ -80,7 +80,7 @@ ArraySeqs хранят свои элементы в приватном [Масс [Вектор](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html) - тип коллекции, который обеспечивает хорошую производительность для всех своих операций. Вектора позволяют получить доступ к любому элементу последовательности за "практически" постоянное время. Это значит что константа больше, чем при получении переднего (`head`) элемента списка или при чтения элемента из ArraySeq, но, тем не менее, это константа. Избегайте использование векторов в алгоритмах базирующихся на активной работе с передними (`head`) элементами. Вектора могут получать доступ к элементам и изменять их в произвольных местах, что делает разработку более простой и удобной. -Вектора создаются и модифицируются также как и другие последовательности. +Вектора создаются и модифицируются так же, как и другие последовательности. scala> val vec = scala.collection.immutable.Vector.empty vec: scala.collection.immutable.Vector[Nothing] = Vector() @@ -91,10 +91,10 @@ ArraySeqs хранят свои элементы в приватном [Масс scala> vec3(0) res1: Int = 100 -Вектора представленны деревьями с высоким уровнем ветвления (уровень ветвления дерева или графа - это количество дочерних элементов у каждого узла). Каждый узел дерева содержит до 32х элементов вектора или содержит до 32х других узлов. Вектора с размером до 32х элементов могут быть представленны одним узлом. Вектора `32 * 32 = 1024` элементы могут быть представлены одним витком. +Вектора представлены деревьями с высоким уровнем ветвления (уровень ветвления дерева или графа - это количество дочерних элементов у каждого узла). Каждый узел дерева содержит до 32х элементов вектора или содержит до 32х других узлов. Вектора с размером до 32х элементов могут быть представлены одним узлом. Вектора `32 * 32 = 1024` элементы могут быть представлены одним витком. Для векторов с 215 элементами достаточно двух переходов от корня дерева до конечного элемента узла, трех переходов для векторов с 220 элементами, четырех переходов для 225 элементами и пяти переходов для 230 элементами. Таким образом, для всех векторов разумных размеров выбор элемента включает до 5 простых выборок массивов. Именно это мы подразумевали, когда писали, что доступ к элементам осуществляется с "практически постоянным временем". -Также как и доступ к элементу, операция обновления в векторах занимает "практически" постоянное время. Добавление элемента в середину вектора может быть выполнено через копирование узла содержащего этот элемент и каждого ссылающегося на него узла, начиная от корня дерева. Это означает, что процесс обновления элемента создает от одного до пяти узлов, каждый из которых содержит до 32 элементов или поддеревьев. Это, конечно, дороже, чем просто обновление элемента в изменяемом массиве, но все же намного дешевле, чем копирование вообще всего вектора. +Так же как и доступ к элементу, операция обновления в векторах занимает "практически" постоянное время. Добавление элемента в середину вектора может быть выполнено через копирование узла содержащего этот элемент и каждого ссылающегося на него узла, начиная от корня дерева. Это означает, что процесс обновления элемента создает от одного до пяти узлов, каждый из которых содержит до 32 элементов или поддеревьев. Это, конечно, дороже, чем просто обновление элемента в изменяемом массиве, но все же намного дешевле, чем копирование вообще всего вектора. Поскольку вектора обладают хорошим балансом между быстрой случайной выборкой и быстрым случайным обновлением элементов, они используются в качестве реализации неизменяемых индексированных последовательностей: @@ -151,7 +151,7 @@ ArraySeqs хранят свои элементы в приватном [Масс Хэш деревья - это стандартный способ эффективного создания неизменяемых множеств и ассоциативных массивов (мап). [Compressed Hash-Array Mapped Prefix-trees](https://github.com/msteindorfer/oopsla15-artifact/) - это специальные хэш деревья для JVM, которые улучшают локальность и обеспечивают компактную и элегантную реализацию деревьев. Они базируются на классе [immutable.HashMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/HashMap.html). Их представление очень похоже на реализацию векторов, которые также являются деревьями, где каждый узел имеет либо 32 элемента либо 32 поддерева. Но в данном случае ключ выбирается на основе хэш-кода. Например, чтобы найти ключ на мапе, сначала берут хэш-код ключа. Затем самые младшие 5 бит хэш-кода используются для выбора первого поддерева, за которым следуют следующие 5 бит и так далее. Выбор прекращается, когда для всех битов будут найдены ключи. -Хэш деревья пытаются предоставить разумный баланс между достаточно быстрым поиском и достаточно эффективными операциями вставки (`+`) и удаления (`-`) элементов. Именно поэтому они лежат в основе стандартных реализаций Scala неизменяемых множеств и ассоциативных массивов (мап). На самом деле, в Scala есть дополнительная оптимизацию для неизменяемых множеств и мап, которые содержат менее пяти элементов. Множества и мапы от одного до четырех элементов хранятся как обычные объекты, которые содержат только элементы (или пары ключ/значение в случае мапы) как поля. Пустое неизменяемое множество и пустая неизменяемая мапа - это всегда объект-сингэлтон - нет необходимости размножать сущности для них, потому что пустое неизменяемое множество или мапа всегда будут оставаться пустыми. +Хэш деревья пытаются предоставить разумный баланс между достаточно быстрым поиском и достаточно эффективными операциями вставки (`+`) и удаления (`-`) элементов. Именно поэтому они лежат в основе стандартных реализаций Scala неизменяемых множеств и ассоциативных массивов (мап). На самом деле, в Scala есть дополнительная оптимизация для неизменяемых множеств и мап, которые содержат менее пяти элементов. Множества и мапы от одного до четырех элементов хранятся как обычные объекты, которые содержат только элементы (или пары ключ/значение в случае мапы) как поля. Пустое неизменяемое множество и пустая неизменяемая мапа - это всегда объект-сингэлтон - нет необходимости размножать сущности для них, потому что пустое неизменяемое множество или мапа всегда будут оставаться пустыми. ## Красно-Черные Деревья (Red-Black Trees) diff --git a/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md b/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md index d6f23a7024..1506db43ce 100644 --- a/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md +++ b/_ru/overviews/collections-2.13/concrete-mutable-collection-classes.md @@ -13,7 +13,7 @@ language: ru ## Array Buffers -[ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) - буферизированный массив в своем буфере хранит массив и его размер. Большинство операций с буферизированным массивом выполняются с той же скоростью, что и с массивом, так как операции просто обращаются и изменяют исходный массив. Кроме того он может эффективно добавлять данные к своему концу. Присоединение элемента к такому массиву занимает амортизированное константное время. Поэтому буферизированные массивы будут полезны, если вы строите большую коллекцию данных регулярно добавляя новые элементы в конец. +[ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) - буферизированный массив в своем буфере хранит массив и его размер. Большинство операций с буферизированным массивом выполняются с той же скоростью, что и с массивом, так как операции просто обращаются и изменяют исходный массив. Кроме того, он может эффективно добавлять данные к своему концу. Присоединение элемента к такому массиву занимает амортизированное константное время. Поэтому буферизированные массивы будут полезны, если вы строите большую коллекцию данных регулярно добавляя новые элементы в конец. scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int] buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() @@ -39,7 +39,7 @@ language: ru ## StringBuilders -Так же, как буферизированный массив полезен для создания массивов, а буферизированный список полезен для построения списков, [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) полезен для создания строк. StringBuilders настолько широко используются, что они уже импортированы по умолчанию в стандартную область видимости. Можете создать их с помощью `new StringBuilder`, как в следующем примере: +Так же как буферизированный массив полезен для создания массивов, а буферизированный список полезен для построения списков, [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) полезен для создания строк. StringBuilders настолько широко используются, что они уже импортированы по умолчанию в стандартную область видимости. Можете создать их с помощью `new StringBuilder`, как в следующем примере: scala> val buf = new StringBuilder buf: StringBuilder = @@ -144,7 +144,7 @@ Scala предоставляет не только неизменяемые, н ## Mutable Bitsets (Изменяемый Битовый Набор) -Изменяемый набор типа [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) практически такойже как и неизменяемый набор, за исключением того, что он при изменении сам меняется. Изменяемые битовые наборы немного эффективнее при обновлении, чем неизменяемые, так как им не нужно копировать `Long`, которые не изменились. +Изменяемый набор типа [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) практически такой же, как и неизменяемый набор, за исключением того, что он при изменении сам меняется. Изменяемые битовые наборы немного эффективнее при обновлении, чем неизменяемые, так как им не нужно копировать `Long`, которые не изменились. scala> val bits = scala.collection.mutable.BitSet.empty bits: scala.collection.mutable.BitSet = BitSet() diff --git a/_ru/overviews/collections-2.13/creating-collections-from-scratch.md b/_ru/overviews/collections-2.13/creating-collections-from-scratch.md index 25c9cb21cf..5956c8e4a2 100644 --- a/_ru/overviews/collections-2.13/creating-collections-from-scratch.md +++ b/_ru/overviews/collections-2.13/creating-collections-from-scratch.md @@ -49,7 +49,7 @@ language: ru | `C.empty` | Пустая коллекция. | | `C(x, y, z)` | Коллекция состоящая из элементов `x, y, z`. | | `C.concat(xs, ys, zs)` | Коллекция, полученная путем объединения элементов `xs, ys, zs`. | -| `C.fill(n){e}` | Коллекция длины `n`, где каждый элемент вычисляется выражением`e`. | +| `C.fill(n){e}` | Коллекция длины `n`, где каждый элемент вычисляется выражением `e`. | | `C.fill(m, n){e}` | Коллекция коллекций размерности `m×n`, где каждый элемент вычисляется выражением `e`. (существует и в более высоких измерениях). | | `C.tabulate(n){f}` | Коллекция длины `n`, где элемент каждого индекса i вычисляется с помощью `f(i)`. | | `C.tabulate(m, n){f}` | Коллекция коллекций измерений `m×n`, где элемент каждого индекса `(i, j)` вычисляется с помощью `f(i, j)`. (существует также в более высоких измерениях). | diff --git a/_ru/overviews/collections-2.13/equality.md b/_ru/overviews/collections-2.13/equality.md index 179ae0bd71..e05ee5ee73 100644 --- a/_ru/overviews/collections-2.13/equality.md +++ b/_ru/overviews/collections-2.13/equality.md @@ -9,7 +9,7 @@ next-page: views language: ru --- -Коллекций придерживаются единого подхода к определению равенства и получению хэшей. Идея состоит, во-первых, в том, чтобы разделить коллекции на группы: множества, мапы и последовательности. Коллекции в разных группах всегда различаются. Например, `Set(1,2,3)` неравнозначен списку `List(1,2,3)`, хотя они содержат одни и те же элементы. С другой стороны, в рамках одной и той же группы коллекции равны тогда и только тогда, когда они имеют одинаковые элементы (для последовательностей: одни и те же элементы в одном порядке). Например `List(1, 2, 3) == Vector(1, 2, 3)`, и `HashSet(1, 2) == TreeSet(2, 1)`. +Коллекции придерживаются единого подхода к определению равенства и получению хэшей. Идея состоит, во-первых, в том, чтобы разделить коллекции на группы: множества, мапы и последовательности. Коллекции в разных группах всегда различаются. Например, `Set(1,2,3)` неравнозначен списку `List(1,2,3)`, хотя они содержат одни и те же элементы. С другой стороны, в рамках одной и той же группы коллекции равны тогда и только тогда, когда они имеют одинаковые элементы (для последовательностей: одни и те же элементы в одном порядке). Например `List(1, 2, 3) == Vector(1, 2, 3)`, и `HashSet(1, 2) == TreeSet(2, 1)`. Для проверки на равенство не важно, является ли коллекция изменяемой или неизменяемой. Для изменяемой коллекции достаточно просто рассмотреть ее текущие элементы на момент проведения проверки на равенство. Это означает, что коллекция в разные моменты может быть эквивалентна разным коллекциям, в зависимости от того, какие элементы в неё добавляются или удаляются. В этом кроится потенциальная опасность при использовании изменяемой коллекции в качестве ключа для хэшмапы. Пример: diff --git a/_ru/overviews/collections-2.13/iterators.md b/_ru/overviews/collections-2.13/iterators.md index a74e0bc860..3d43d76a8f 100644 --- a/_ru/overviews/collections-2.13/iterators.md +++ b/_ru/overviews/collections-2.13/iterators.md @@ -56,8 +56,8 @@ language: ru Обратите внимание еще раз, что сам итератор`it` был изменен вызовом `dropWhile`: теперь он указывает на второе слово `number` в списке. Фактически, `it` и результат `res4` возвращаемый после`dropWhile` возвращают одну и туже последовательность элементов. -Чтоб избежать такое поведение, как вариант можно использовать `duplicate` (дублировать используемый итератор), вызывая методы на разных итераторах. -Каждый из _двух_ итераторов будет обрабатывать точно такие же элементы, как и тот из которого состоит итераторатор `it`: +Чтобы избежать такое поведение, как вариант можно использовать `duplicate` (дублировать используемый итератор), вызывая методы на разных итераторах. +Каждый из _двух_ итераторов будет обрабатывать точно такие же элементы, как и тот, из которого состоит итераторатор `it`: scala> val (words, ns) = Iterator("a", "number", "of", "words").duplicate words: Iterator[String] = @@ -73,7 +73,7 @@ language: ru Может создаться впечатление что итератор подвергается двойному обходу над элементами, но это не так, результат достигается за счет внутреннего буферизации. Как обычно, базовый итератор `it` не пригоден для прямого использования и должен быть исключен из дальнейших операций. -Обобщая вышесказанное, итераторы ведут себя как коллекции _если после вызова метода на них сам итератор больше не вызывается_. В библиотеке коллекции Scala это достигается явным образом с помощью абстракции [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html), который является общим суперкласом для [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) и [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html). У `IterableOnce[A]` только два метода: `iterator: Iterator[A]` и `knownSize: Int`. +Обобщая вышесказанное, итераторы ведут себя как коллекции, _если после вызова метода на них сам итератор больше не вызывается_. В библиотеке коллекции Scala это достигается явным образом с помощью абстракции [IterableOnce](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/IterableOnce.html), который является общим суперкласом для [Iterable](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterable.html) и [Iterator](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html). У `IterableOnce[A]` только два метода: `iterator: Iterator[A]` и `knownSize: Int`. Если объект `IterableOnce` является `Iterator`, то его операция `iterator` всегда возвращает себя, в своем текущем состоянии, но если он `Iterable`, то операция `iterator` всегда возвращает новый `Iterator`. Типовой вариант использования `IterableOnce` - в качестве типа аргумента для методов, которые могут принимать или итератор или коллекцию в качестве аргумента. Примером может служить метод соединения `concat` в классе `Iterable`. Он принимает `IterableOnce` параметр, поэтому вы можете соединять элементы, поступающие или из итератора или коллекции. @@ -168,7 +168,7 @@ language: ru Поэтому выражение `(1 to 10).iterator.map(println)` не выведет ничего на экран. Метод `map` в данном случае не применяет функцию в аргументе к значениям в диапазоне, вместо этого будет возвращен новый `Iterator`, который будет выполнять операции тогда когда будет запрошен их результат. Добавление `.toList` в конец этого выражения фактически вызовет вывод элементов на печать. -Как следствие такие методы как `map` или `filter` не обязательно применят функцию в аргументе ко всем входным элементам. Выражение `(1 to 10).iterator.map(println).take(5).toList` выводит только значения от `1` до `5`, поскольку это те значения, которые запрашиваются у `Iterator`, возвращаемого из `map`. +Как следствие, такие методы как `map` или `filter` не обязательно применят функцию в аргументе ко всем входным элементам. Выражение `(1 to 10).iterator.map(println).take(5).toList` выводит только значения от `1` до `5`, поскольку это те значения, которые запрашиваются у `Iterator`, возвращаемого из `map`. Это одна из причин, того почему важно использовать только чистые функции в качестве аргументов для `map`, `filter`, `fold` и подобных методов. Помните, что чистая функция не имеет побочных эффектов, поэтому `println` обычно не используется в `map`. Здесь `println` используется лишь для демонстрации "ленивости", которую с чистыми функциями не заметно. diff --git a/_ru/overviews/collections-2.13/overview.md b/_ru/overviews/collections-2.13/overview.md index 6eb7087c63..c9205aeded 100644 --- a/_ru/overviews/collections-2.13/overview.md +++ b/_ru/overviews/collections-2.13/overview.md @@ -23,7 +23,7 @@ language: ru является _базовой_ для обоих коллекций [collection.immutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/IndexedSeq.html) и [collection.mutable.IndexedSeq\[T\]](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/IndexedSeq.html) -Как правило, базовые коллекции пакета `scala.collection` поддерживают операции преобразования, затрагивающие всю коллекцию, неизменяемые коллекции пакета `scala.collection.immutable` обычно добавляют операции добавления или удаления отдельных элементов, а изменяемые коллекции пакета `scala.collection.mutable` обычно добавляют к базовому интерфейсу, операции модификации элементов основанные на побочных эфектах. +Как правило, базовые коллекции пакета `scala.collection` поддерживают операции преобразования, затрагивающие всю коллекцию, неизменяемые коллекции пакета `scala.collection.immutable` обычно добавляют операции добавления или удаления отдельных элементов, а изменяемые коллекции пакета `scala.collection.mutable` обычно добавляют к базовому интерфейсу операции модификации элементов, основанные на побочных эффектах. Еще одним отличием базовой коллекции от неизменяемой является то, что пользователи неизменяемой коллекции имеют гарантию, что никто не сможет изменить коллекцию, а пользователи базовой коллекции лишь обещают не менять ее самостоятельно. Даже если тип такой коллекции не предоставляет никаких операций для модификации коллекции, все равно возможно, что эта коллекция, может быть изменена какими-либо сторонними пользователями. diff --git a/_ru/overviews/collections-2.13/performance-characteristics.md b/_ru/overviews/collections-2.13/performance-characteristics.md index eb63206c02..281280075b 100644 --- a/_ru/overviews/collections-2.13/performance-characteristics.md +++ b/_ru/overviews/collections-2.13/performance-characteristics.md @@ -9,7 +9,7 @@ next-page: equality language: ru --- -Из предыдущих объяснений стало ясно, что разные типы коллекций имеют разные показатели производительности. Что зачастую является основной причиной, выбора одной коллекции вместо другой. Показатели для наиболее распространенных операций собраны в таблицах ниже. +Из предыдущих объяснений стало ясно, что разные типы коллекций имеют разные показатели производительности. Что зачастую является основной причиной выбора одной коллекции вместо другой. Показатели для наиболее распространенных операций собраны в таблицах ниже. Показатели производительности на последовательностях: diff --git a/_ru/overviews/collections-2.13/seqs.md b/_ru/overviews/collections-2.13/seqs.md index bf67f53cf0..49ef6d32b6 100644 --- a/_ru/overviews/collections-2.13/seqs.md +++ b/_ru/overviews/collections-2.13/seqs.md @@ -73,7 +73,7 @@ language: ru | `xs distinctBy f` |Подпоследовательность `xs`, которая не содержит дублирующего элемента после применения функции преобразования `f`. Например, `List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "quux")`| У трейта [Seq](https://www.scala-lang.org/api/current/scala/collection/Seq.html) есть два дочерних трейта [LinearSeq](https://www.scala-lang.org/api/current/scala/collection/LinearSeq.html), и [IndexedSeq](https://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html). -Они не добавляют никаких новых операций, но у каждого из них разные характеристики производительности: у LinearSeq эффективные операции `head` и `tail`, в то время как у IndexedSeq эффективные операции `apply`, `length` и (если мутабельная) `update`. Часто используемые варианты LinearSeq - это `scala.collection.immutable.List` и `scala.collection.immutable.LazyList`. А наиболее часто используемые IndexedSeq - это `scala.Array` и `scala.collection.mutable.ArrayBuffer`. Класс `Vector` представляет собой компромисс между IndexedSeq и LinearSeq. У него эффективные, как обращение по индексу, так и последовательный обход элементов. Поэтому вектора хорошая основа для смешанных моделей доступа, где используются как индексированный, так и последовательный доступ. Позже мы расскажем больше о [векторах]({% link _ru/overviews/collections-2.13/concrete-immutable-collection-classes.md %}). +Они не добавляют никаких новых операций, но у каждого из них разные характеристики производительности: у LinearSeq эффективные операции `head` и `tail`, в то время как у IndexedSeq эффективные операции `apply`, `length` и (если мутабельная) `update`. Часто используемые варианты LinearSeq - это `scala.collection.immutable.List` и `scala.collection.immutable.LazyList`. А наиболее часто используемые IndexedSeq - это `scala.Array` и `scala.collection.mutable.ArrayBuffer`. Класс `Vector` представляет собой компромисс между IndexedSeq и LinearSeq. У него эффективные как обращение по индексу, так и последовательный обход элементов. Поэтому вектора хорошая основа для смешанных моделей доступа, где используются как индексированный, так и последовательный доступ. Позже мы расскажем больше о [векторах]({% link _ru/overviews/collections-2.13/concrete-immutable-collection-classes.md %}). В мутабельном варианте `IndexedSeq` добавляет операции преобразования ее элементов в самой коллекции (в отличие от таких операций как `map` и `sort`, доступных на базовом трейте `Seq`, для которых результат - это новая коллекция). diff --git a/_ru/overviews/collections-2.13/sets.md b/_ru/overviews/collections-2.13/sets.md index 20becc4ffa..d57e891797 100644 --- a/_ru/overviews/collections-2.13/sets.md +++ b/_ru/overviews/collections-2.13/sets.md @@ -112,7 +112,7 @@ language: ru Два дочерних трейта множеств `SortedSet` и `BitSet`. ### Отсортированное Множество (SortedSet) ### -[SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) это множество, которое отдает свои элементы (используя `iterator` или `foreach`) в заданном порядке (который можно свободно задать в момент создания множества). Стандартное представление [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) - это упорядоченное двоичное дерево, которое поддерживает свойство того, что все элементы левого поддерева меньше, чем все элементы правого поддерева. Таким образом, простой упорядоченный обход может вернуть все элементы дерева в возрастающем порядке. Scala класс [immutable.TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) базируется на _красно-черном_ дереве, в котором сохраняется тоже свойство но при этом само дерево является _сбалансированным_ --, то есть все пути от корня дерева до листа имеют длину, которая может отличаться друг от друга максимум на еденицу. +[SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) это множество, которое отдает свои элементы (используя `iterator` или `foreach`) в заданном порядке (который можно свободно задать в момент создания множества). Стандартное представление [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet.html) - это упорядоченное двоичное дерево, которое поддерживает свойство того, что все элементы левого поддерева меньше, чем все элементы правого поддерева. Таким образом, простой упорядоченный обход может вернуть все элементы дерева в возрастающем порядке. Scala класс [immutable.TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) базируется на _красно-черном_ дереве, в котором сохраняется тоже свойство но при этом само дерево является _сбалансированным_ --, то есть все пути от корня дерева до листа имеют длину, которая может отличаться друг от друга максимум на единицу. При создании пустого [TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html), можно сначала указать требуемый порядок: @@ -129,7 +129,7 @@ language: ru scala> TreeSet.empty[String] res2: scala.collection.immutable.TreeSet[String] = TreeSet() -Если вы создаете новое множество из существующего упорядоченного множества (например, путем объединения или фильтрации), оно будет иметь туже схему упорядочения элементов, что и исходное множество. Например +Если вы создаете новое множество из существующего упорядоченного множества (например, путем объединения или фильтрации), оно будет иметь ту же схему упорядочения элементов, что и исходное множество. Например scala> res2 + "one" + "two" + "three" + "four" res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two) diff --git a/_ru/overviews/collections-2.13/strings.md b/_ru/overviews/collections-2.13/strings.md index 17e13d1a14..141b537e76 100644 --- a/_ru/overviews/collections-2.13/strings.md +++ b/_ru/overviews/collections-2.13/strings.md @@ -9,7 +9,7 @@ next-page: performance-characteristics language: ru --- -Как и массивы, строки не являются непосредственно последовательностями, но могут быть преобразованы в них, а также поддерживают все операции которые есть у последовательностей. Ниже приведены некоторые примеры операций, которые можно вызывать на строках. +Как и массивы, строки не являются непосредственно последовательностями, но могут быть преобразованы в них, а также поддерживают все операции, которые есть у последовательностей. Ниже приведены некоторые примеры операций, которые можно вызывать на строках. scala> val str = "hello" str: java.lang.String = hello diff --git a/_ru/overviews/collections-2.13/trait-iterable.md b/_ru/overviews/collections-2.13/trait-iterable.md index b02ffd19a1..3af59d11d6 100644 --- a/_ru/overviews/collections-2.13/trait-iterable.md +++ b/_ru/overviews/collections-2.13/trait-iterable.md @@ -31,7 +31,7 @@ language: ru * **Строковая** операции `mkString`, `addString`, `className`, которые дают альтернативные способы преобразования коллекции в строку. * **Отображения** - это такая коллекция, которая лениво вычисляется. Позже мы расмотрим отображения [подробнее]({% link _ru/overviews/collections-2.13/views.md %}). -В `Iterable` есть два метода, которые возвращают итераторы: `grouped` и `sliding`. Правда эти итераторы возвращают не отдельные элементы, а целые подпоследовательности элементов исходной коллекции. Максимальный размер таких подпоследовательностей задается аргументом. Метод `grouped` возвращает свои элементы "нарезанные" на фиксированные части, тогда как `sliding` возвращает результат "прохода окна" (заданной длинны) над элементами. Разница между ними станет очевидной, если взглянуть на следующий результат в консоли: +В `Iterable` есть два метода, которые возвращают итераторы: `grouped` и `sliding`. Правда, эти итераторы возвращают не отдельные элементы, а целые подпоследовательности элементов исходной коллекции. Максимальный размер таких подпоследовательностей задается аргументом. Метод `grouped` возвращает свои элементы "нарезанные" на фиксированные части, тогда как `sliding` возвращает результат "прохода окна" (заданной длинны) над элементами. Разница между ними станет очевидной, если взглянуть на следующий результат в консоли: scala> val xs = List(1, 2, 3, 4, 5) xs: List[Int] = List(1, 2, 3, 4, 5) diff --git a/_ru/overviews/collections-2.13/views.md b/_ru/overviews/collections-2.13/views.md index 3b8a5f5d76..a26760f360 100644 --- a/_ru/overviews/collections-2.13/views.md +++ b/_ru/overviews/collections-2.13/views.md @@ -34,7 +34,7 @@ language: ru res5: scala.collection.immutable.Vector[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22) -В последней строчке выражение `v map (_ + 1)` создает новый вектор, который при втором вызове в `map (_ * 2)` превращается в третий вектор. Как правило построение промежуточного результата от первого вызова мапы расточительно. В приведенном выше примере было бы быстрее составить единую мапу, состоящую из двух функций `(_ + 1)` и `(_ * 2)`. Если у вас обе функции доступны в одном и том же выражении, вы можете объеденить их вручную. Но довольно часто последовательные преобразования структуры данных выполняются в различных модулях программы. Слияние этих преобразований отрицательно скажется на модульности. Более универсальным способом избежать промежуточных результатов - это превратить вектор сначало в отображение, затем примененить все преобразования к отображению и, наконец, преобразовать отображение в вектор: +В последней строчке выражение `v map (_ + 1)` создает новый вектор, который при втором вызове в `map (_ * 2)` превращается в третий вектор. Как правило, построение промежуточного результата от первого вызова мапы расточительно. В приведенном выше примере было бы быстрее составить единую мапу, состоящую из двух функций `(_ + 1)` и `(_ * 2)`. Если у вас обе функции доступны в одном и том же выражении, вы можете объединить их вручную. Но довольно часто последовательные преобразования структуры данных выполняются в различных модулях программы. Слияние этих преобразований отрицательно скажется на модульности. Более универсальным способом избежать промежуточных результатов - это превратить вектор сначало в отображение, затем применить все преобразования к отображению и, наконец, преобразовать отображение в вектор: scala> (v.view map (_ + 1) map (_ * 2)).to(Vector) res12: scala.collection.immutable.Vector[Int] = @@ -45,7 +45,7 @@ language: ru scala> val vv = v.view vv: scala.collection.IndexedSeqView[Int] = IndexedSeqView() -Применение `v.view` дает нам `IndexedSeqView[Int]`, тоесть лениво вычисляемым `IndexedSeq[Int]`. Также как и `LazyList`, +Применение `v.view` дает нам `IndexedSeqView[Int]`, тоесть лениво вычисляемым `IndexedSeq[Int]`. Так же как и `LazyList`, метод `toString` на отображении не принуждает выводить элементы, вот почему содержимое `vv` выводится как `View(?)`. Применение первого `map` к отображению дает: