diff --git a/_overviews/scala3-book/types-adts-gadts.md b/_overviews/scala3-book/types-adts-gadts.md
index a4f31e0040..204519c030 100644
--- a/_overviews/scala3-book/types-adts-gadts.md
+++ b/_overviews/scala3-book/types-adts-gadts.md
@@ -2,7 +2,7 @@
title: Algebraic Data Types
type: section
description: This section introduces and demonstrates algebraic data types (ADTs) in Scala 3.
-languages: [zh-cn]
+languages: [ru, zh-cn]
num: 53
previous-page: types-union
next-page: types-variance
diff --git a/_overviews/scala3-book/types-variance.md b/_overviews/scala3-book/types-variance.md
index 7aae5b5fac..deb2492e80 100644
--- a/_overviews/scala3-book/types-variance.md
+++ b/_overviews/scala3-book/types-variance.md
@@ -2,7 +2,7 @@
title: Variance
type: section
description: This section introduces and demonstrates variance in Scala 3.
-languages: [zh-cn]
+languages: [ru, zh-cn]
num: 54
previous-page: types-adts-gadts
next-page: types-opaque-types
diff --git a/_ru/scala3/book/types-adts-gadts.md b/_ru/scala3/book/types-adts-gadts.md
new file mode 100644
index 0000000000..199d7f1f33
--- /dev/null
+++ b/_ru/scala3/book/types-adts-gadts.md
@@ -0,0 +1,222 @@
+---
+layout: multipage-overview
+title: Алгебраические типы данных
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлены и демонстрируются алгебраические типы данных (ADT) в Scala 3.
+language: ru
+num: 53
+previous-page: types-union
+next-page: types-variance
+---
+
+Только в Scala 3
+
+Алгебраические типы данных (ADT) могут быть созданы с помощью конструкции `enum`,
+поэтому кратко рассмотрим перечисления, прежде чем рассматривать ADT.
+
+## Перечисления
+
+_Перечисление_ используется для определения типа, состоящего из набора именованных значений:
+
+```scala
+enum Color:
+ case Red, Green, Blue
+```
+
+который можно рассматривать как сокращение для:
+
+```scala
+enum Color:
+ case Red extends Color
+ case Green extends Color
+ case Blue extends Color
+```
+
+#### Параметры
+
+Перечисления могут быть параметризованы:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+```
+
+Таким образом, каждый из различных вариантов содержит параметр `rgb`,
+которому присваивается соответствующее значение:
+
+```scala
+println(Color.Green.rgb) // выводит 65280
+```
+
+#### Пользовательские определения
+
+Перечисления также могут содержать пользовательские определения:
+
+```scala
+enum Planet(mass: Double, radius: Double):
+
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+
+ case Mercury extends Planet(3.303e+23, 2.4397e6)
+ case Venus extends Planet(4.869e+24, 6.0518e6)
+ case Earth extends Planet(5.976e+24, 6.37814e6)
+ // остальные 5 или 6 планет ...
+```
+
+Подобно классам и `case` классам, вы также можете определить сопутствующий объект для перечисления:
+
+```scala
+object Planet:
+ def main(args: Array[String]) =
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight / Earth.surfaceGravity
+ for (p <- values)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+```
+
+## Алгебраические типы данных (ADTs)
+
+Концепция `enum` является достаточно общей,
+чтобы также поддерживать _алгебраические типы данных_ (ADT) и их обобщенную версию (GADT).
+Вот пример, показывающий, как тип `Option` может быть представлен в виде АТД:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+```
+
+В этом примере создается перечисление `Option` с параметром ковариантного типа `T`,
+состоящим из двух вариантов `Some` и `None`.
+`Some` _параметризуется_ значением параметра `x`;
+это сокращение для написания `case` класса, расширяющего `Option`.
+Поскольку `None` не параметризуется, то он считается обычным enum значением.
+
+Предложения `extends`, которые были опущены в предыдущем примере, также могут быть указаны явно:
+
+```scala
+enum Option[+T]:
+ case Some(x: T) extends Option[T]
+ case None extends Option[Nothing]
+```
+
+Как и в случае с обычным `enum` значениями, варианты enum определяются в его сопутствующем объекте,
+поэтому они называются `Option.Some` и `Option.None` (если только определения не «вытягиваются» при импорте):
+
+```scala
+scala> Option.Some("hello")
+val res1: t2.Option[String] = Some(hello)
+
+scala> Option.None
+val res2: t2.Option[Nothing] = None
+```
+
+Как и в других случаях использования перечисления, АТД могут определять дополнительные методы.
+Например, вот снова `Option`, с методом `isDefined` и конструктором `Option(...)` в сопутствующем объекте:
+
+```scala
+enum Option[+T]:
+ case Some(x: T)
+ case None
+
+ def isDefined: Boolean = this match
+ case None => false
+ case Some(_) => true
+
+object Option:
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+```
+
+Перечисления и АТД используют одну и ту же синтаксическую конструкцию,
+поэтому их можно рассматривать просто как два конца спектра, и вполне допустимо создавать гибриды.
+Например, приведенный ниже код реализует `Color` либо с тремя значениями перечисления,
+либо с параметризованным вариантом, принимающим значение RGB:
+
+```scala
+enum Color(val rgb: Int):
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+```
+
+#### Рекурсивные перечисления
+
+До сих пор все перечисления, которые мы определяли, состояли из различных вариантов значений или case классов.
+Перечисления также могут быть рекурсивными, как показано в приведенном ниже примере кодирования натуральных чисел:
+
+```scala
+enum Nat:
+ case Zero
+ case Succ(n: Nat)
+```
+
+Например, значение `Succ(Succ(Zero))` представляет число `2` в унарной кодировке.
+Списки могут быть определены похожим образом:
+
+```scala
+enum List[+A]:
+ case Nil
+ case Cons(head: A, tail: List[A])
+```
+
+## Обобщенные алгебраические типы данных (GADT)
+
+Приведенная выше нотация для перечислений очень краткая
+и служит идеальной отправной точкой для моделирования ваших типов данных.
+Поскольку мы всегда можем быть более подробными, то можем выразить гораздо более мощные типы:
+обобщенные алгебраические типы данных (GADT).
+
+Вот пример GADT, в котором параметр типа (`T`) указывает на тип содержимого, хранящегося в `Box`:
+
+```scala
+enum Box[T](contents: T):
+ case IntBox(n: Int) extends Box[Int](n)
+ case BoolBox(b: Boolean) extends Box[Boolean](b)
+```
+
+Сопоставление с образцом с конкретным конструктором (`IntBox` или `BoolBox`) восстанавливает информацию о типе:
+
+```scala
+def extract[T](b: Box[T]): T = b match
+ case IntBox(n) => n + 1
+ case BoolBox(b) => !b
+```
+
+Безопасно возвращать `Int` в первом случае, так как мы знаем из сопоставления с образцом, что ввод был `IntBox`.
+
+## Дешугаризация перечислений
+
+_Концептуально_ перечисления можно рассматривать как определение запечатанного класса вместе с сопутствующим ему объектом.
+Давайте посмотрим на дешугаризацию нашего перечисления `Color`:
+
+```scala
+sealed abstract class Color(val rgb: Int) extends scala.reflect.Enum
+object Color:
+ case object Red extends Color(0xFF0000) { def ordinal = 0 }
+ case object Green extends Color(0x00FF00) { def ordinal = 1 }
+ case object Blue extends Color(0x0000FF) { def ordinal = 2 }
+ case class Mix(mix: Int) extends Color(mix) { def ordinal = 3 }
+
+ def fromOrdinal(ordinal: Int): Color = ordinal match
+ case 0 => Red
+ case 1 => Green
+ case 2 => Blue
+ case _ => throw new NoSuchElementException(ordinal.toString)
+```
+
+Заметьте, что вышеописанная дешугаризация упрощена, и мы намеренно опускаем [некоторые детали][desugar-enums].
+
+В то время как перечисления можно кодировать вручную с помощью других конструкций,
+использование перечислений является более кратким,
+а также включает несколько дополнительных утилит (таких, как метод `fromOrdinal`).
+
+[desugar-enums]: {{ site.scala3ref }}/enums/desugarEnums.html
diff --git a/_ru/scala3/book/types-union.md b/_ru/scala3/book/types-union.md
index 6c28497626..6185d59e12 100644
--- a/_ru/scala3/book/types-union.md
+++ b/_ru/scala3/book/types-union.md
@@ -9,7 +9,7 @@ description: В этом разделе представлены объедин
language: ru
num: 52
previous-page: types-intersection
-next-page:
+next-page: types-adts-gadts
---
Только в Scala 3
diff --git a/_ru/scala3/book/types-variance.md b/_ru/scala3/book/types-variance.md
new file mode 100644
index 0000000000..d4a4eaa7b7
--- /dev/null
+++ b/_ru/scala3/book/types-variance.md
@@ -0,0 +1,283 @@
+---
+layout: multipage-overview
+title: Вариантность
+scala3: true
+partof: scala3-book
+overview-name: "Scala 3 — Book"
+type: section
+description: В этом разделе представлена и демонстрируется вариантность в Scala 3.
+language: ru
+num: 54
+previous-page: types-adts-gadts
+next-page:
+---
+
+_Вариантность_ (_variance_) параметра типа управляет подтипом параметризованных типов (таких, как классы или трейты).
+
+Чтобы объяснить вариантность, давайте рассмотрим следующие определения типов:
+
+{% tabs types-variance-1 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+trait Item { def productNumber: String }
+trait Buyable extends Item { def price: Int }
+trait Book extends Buyable { def isbn: String }
+
+```
+
+{% endtab %}
+{% endtabs %}
+
+Предположим также следующие параметризованные типы:
+
+{% tabs types-variance-2 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-2 %}
+
+```scala
+// пример инвариантного типа
+trait Pipeline[T] {
+ def process(t: T): T
+}
+
+// пример ковариантного типа
+trait Producer[+T] {
+ def make: T
+}
+
+// пример контрвариантного типа
+trait Consumer[-T] {
+ def take(t: T): Unit
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-2 %}
+
+```scala
+// пример инвариантного типа
+trait Pipeline[T]:
+ def process(t: T): T
+
+// пример ковариантного типа
+trait Producer[+T]:
+ def make: T
+
+// пример контрвариантного типа
+trait Consumer[-T]:
+ def take(t: T): Unit
+```
+
+{% endtab %}
+{% endtabs %}
+
+В целом существует три режима вариантности (variance):
+
+- **инвариант** (invariant) — значение по умолчанию, написанное как `Pipeline[T]`
+- **ковариантный** (covariant) — помечен знаком `+`, например `Producer[+T]`
+- **контравариантный** (contravariant) — помечен знаком `-`, как в `Consumer[-T]`
+
+Подробнее рассмотрим, что означает и как используется эта аннотация.
+
+### Инвариантные типы
+
+По умолчанию такие типы, как `Pipeline`, инвариантны в своем аргументе типа (в данном случае `T`).
+Это означает, что такие типы, как `Pipeline[Item]`, `Pipeline[Buyable]` и `Pipeline[Book]`, _не являются подтипами_ друг друга.
+
+И это правильно! Предположим, что следующий метод использует два значения (`b1`, `b2`) типа `Pipeline[Buyable]`
+и передает свой аргумент `b` методу `process` при его вызове на `b1` и `b2`:
+
+{% tabs types-variance-3 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-3 %}
+
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable = {
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if (b1.price < b2.price) b1 else b2
+ }
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-3 %}
+
+```scala
+def oneOf(
+ p1: Pipeline[Buyable],
+ p2: Pipeline[Buyable],
+ b: Buyable
+): Buyable =
+ val b1 = p1.process(b)
+ val b2 = p2.process(b)
+ if b1.price < b2.price then b1 else b2
+```
+
+{% endtab %}
+{% endtabs %}
+
+Теперь вспомните, что у нас есть следующие _отношения подтипов_ между нашими типами:
+
+{% tabs types-variance-4 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+Book <: Buyable <: Item
+```
+
+{% endtab %}
+{% endtabs %}
+
+Мы не можем передать `Pipeline[Book]` методу `oneOf`,
+потому что в реализации `oneOf` мы вызываем `p1` и `p2` со значением типа `Buyable`.
+`Pipeline[Book]` ожидает `Book`, что потенциально может вызвать ошибку времени выполнения.
+
+Мы не можем передать `Pipeline[Item]`, потому что вызов `process` обещает вернуть `Item`;
+однако мы должны вернуть `Buyable`.
+
+#### Почему Инвариант?
+
+На самом деле тип `Pipeline` должен быть инвариантным,
+так как он использует свой параметр типа `T` _и в качестве_ аргумента, _и в качестве_ типа возвращаемого значения.
+По той же причине некоторые типы в библиотеке коллекций Scala, такие как `Array` или `Set`, также являются _инвариантными_.
+
+### Ковариантные типы
+
+В отличие от `Pipeline`, который является инвариантным,
+тип `Producer` помечается как **ковариантный** (covariant) путем добавления к параметру типа префикса `+`.
+Это допустимо, так как параметр типа используется только в качестве типа _возвращаемого_ значения.
+
+Пометка типа как ковариантного означает, что мы можем передать (или вернуть) `Producer[Book]` там,
+где ожидается `Producer[Buyable]`. И на самом деле, это разумно.
+Тип `Producer[Buyable].make` только обещает _вернуть_ `Buyable`.
+Но для пользователей `make`, так же допустимо принять `Book`, который является подтипом `Buyable`,
+то есть это _по крайней мере_ `Buyable`.
+
+Это иллюстрируется следующим примером, где функция `makeTwo` ожидает `Producer[Buyable]`:
+
+{% tabs types-variance-5 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+def makeTwo(p: Producer[Buyable]): Int =
+ p.make.price + p.make.price
+```
+
+{% endtab %}
+{% endtabs %}
+
+Допустимо передать в `makeTwo` производителя книг:
+
+{% tabs types-variance-6 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val bookProducer: Producer[Book] = ???
+makeTwo(bookProducer)
+```
+
+{% endtab %}
+{% endtabs %}
+
+Вызов `price` в рамках `makeTwo` по-прежнему действителен и для `Book`.
+
+#### Ковариантные типы для неизменяемых контейнеров
+
+Ковариантность чаще всего встречается при работе с неизменяемыми контейнерами, такими как `List`, `Seq`, `Vector` и т.д.
+
+Например, `List` и `Vector` определяются приблизительно так:
+
+{% tabs types-variance-7 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+class List[+A] ...
+class Vector[+A] ...
+```
+
+{% endtab %}
+{% endtabs %}
+
+Таким образом, можно использовать `List[Book]` там, где ожидается `List[Buyable]`.
+Это также интуитивно имеет смысл: если ожидается коллекция вещей, которые можно купить,
+то вполне допустимо получить коллекцию книг.
+В примере выше у книг есть дополнительный метод `isbn`, но дополнительные возможности можно игнорировать.
+
+### Контравариантные типы
+
+В отличие от типа `Producer`, который помечен как ковариантный,
+тип `Consumer` помечен как **контравариантный** (contravariant) путем добавления к параметру типа префикса `-`.
+Это допустимо, так как параметр типа используется только _в позиции аргумента_.
+
+Пометка его как контравариантного означает, что можно передать (или вернуть) `Consumer[Item]` там,
+где ожидается `Consumer[Buyable]`.
+То есть у нас есть отношение подтипа `Consumer[Item] <: Consumer[Buyable]`.
+Помните, что для типа `Producer` все было наоборот, и у нас был `Producer[Buyable] <: Producer[Item]`.
+
+И в самом деле, это разумно. Метод `Consumer[Item].take` принимает `Item`.
+Как вызывающий `take`, мы также можем предоставить `Buyable`, который будет с радостью принят `Consumer[Item]`,
+поскольку `Buyable` — это подтип `Item`, то есть, _по крайней мере_, `Item`.
+
+#### Контравариантные типы для потребителей
+
+Контравариантные типы встречаются гораздо реже, чем ковариантные типы.
+Как и в нашем примере, вы можете думать о них как о «потребителях».
+Наиболее важным типом, помеченным как контравариантный, с которым можно столкнуться, является тип функций:
+
+{% tabs types-variance-8 class=tabs-scala-version %}
+{% tab 'Scala 2' for=types-variance-8 %}
+
+```scala
+trait Function[-A, +B] {
+ def apply(a: A): B
+}
+```
+
+{% endtab %}
+
+{% tab 'Scala 3' for=types-variance-8 %}
+
+```scala
+trait Function[-A, +B]:
+ def apply(a: A): B
+```
+
+{% endtab %}
+{% endtabs %}
+
+Тип аргумента `A` помечен как контравариантный `A` — он использует значения типа `A`.
+Тип результата `B`, напротив, помечен как ковариантный — он создает значения типа `B`.
+
+Вот несколько примеров, иллюстрирующих отношения подтипов, вызванные аннотациями вариантности функций:
+
+{% tabs types-variance-9 %}
+{% tab 'Scala 2 и 3' %}
+
+```scala
+val f: Function[Buyable, Buyable] = b => b
+
+// OK - допустимо вернуть Buyable там, где ожидается Item
+val g: Function[Buyable, Item] = f
+
+// OK - допустимо передать аргумент Book туда, где ожидается Buyable
+val h: Function[Book, Buyable] = f
+```
+
+{% endtab %}
+{% endtabs %}
+
+## Резюме
+
+В этом разделе были рассмотрены три различных вида вариантности:
+
+- **Producers** обычно ковариантны и помечают свой параметр типа со знаком `+`.
+ Это справедливо и для неизменяемых коллекций.
+- **Consumers** обычно контравариантны и помечают свой параметр типа со знаком `-`.
+- Типы, которые являются **одновременно** производителями и потребителями,
+ должны быть инвариантными и не требуют какой-либо маркировки для параметра своего типа.
+ В эту категорию, в частности, попадают изменяемые коллекции, такие как `Array`.