Skip to content

Commit

Permalink
grammar corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
evgeny-rybnikov authored and evgeny-rybnikov committed Jul 20, 2023
1 parent cd240a8 commit 4e51e62
Show file tree
Hide file tree
Showing 13 changed files with 27 additions and 28 deletions.
9 changes: 4 additions & 5 deletions _ru/overviews/collections-2.13/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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] = {
Expand Down
Loading

0 comments on commit 4e51e62

Please sign in to comment.