Skip to content

Add ca given imports in ru #2884

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-given-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Given Imports
type: section
description: This page demonstrates how 'given' import statements work in Scala 3.
languages: [zh-cn]
languages: [ru, zh-cn]
num: 63
previous-page: ca-context-bounds
next-page: ca-type-classes
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-type-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Type Classes
type: section
description: This page demonstrates how to create and use type classes.
languages: [zh-cn]
languages: [ru, zh-cn]
num: 64
previous-page: ca-given-imports
next-page: ca-multiversal-equality
Expand Down
2 changes: 1 addition & 1 deletion _ru/scala3/book/ca-context-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description: В этой главе представлены контекстн
language: ru
num: 62
previous-page: ca-context-parameters
next-page:
next-page: ca-given-imports
---

Во многих ситуациях имя [контекстного параметра]({% link _overviews/scala3-book/ca-context-parameters.md %}#context-parameters)
Expand Down
54 changes: 54 additions & 0 deletions _ru/scala3/book/ca-given-imports.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
layout: multipage-overview
title: Given импорты
scala3: true
partof: scala3-book
overview-name: "Scala 3 — Book"
type: section
description: На этой странице показано, как работают операторы импорта 'given' в Scala 3.
language: ru
num: 63
previous-page: ca-context-bounds
next-page: ca-type-classes
versionSpecific: true
---

Для большей ясности, откуда берутся данные в текущей области видимости,
для импорта экземпляров `given` используется специальная форма оператора `import`.
Базовая форма показана в этом примере:

```scala
object A:
class TC
given tc: TC = ???
def f(using TC) = ???

object B:
import A.* // импорт всех не-given элементов
import A.given // импорт экземпляров given
```

В этом коде предложение `import A.*` объекта `B` импортирует все элементы `A`, _кроме_ `given` экземпляра `tc`.
И наоборот, второй импорт, `import A.given`, импортирует _только_ экземпляр `given`.
Два предложения импорта также могут быть объединены в одно:

```scala
object B:
import A.{given, *}
```

## Обсуждение

Селектор с подстановочным знаком `*` помещает в область видимости все определения, кроме given-ов или расширений,
тогда как селектор `given` помещает в область видимости _все_ given-ы, включая те, которые являются результатом расширений.

Эти правила имеют два основных преимущества:

- понятнее, откуда берутся данные в текущей области видимости.
В частности, невозможно скрыть импортированные given-ы в длинном списке других импортов.
- есть возможность импортировать все given, не импортируя ничего другого.
Это важно, потому что given-ы могут быть анонимными, поэтому обычное использование именованного импорта нецелесообразно.

Дополнительные примеры синтаксиса "import given" показаны в главе ["Пакеты и импорт"][imports].

[imports]: {% link _overviews/scala3-book/packaging-imports.md %}
230 changes: 230 additions & 0 deletions _ru/scala3/book/ca-type-classes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
---
layout: multipage-overview
title: Классы типов
scala3: true
partof: scala3-book
overview-name: "Scala 3 — Book"
type: section
description: В этой главе демонстрируется создание и использование классов типов.
language: ru
num: 64
previous-page: ca-given-imports
next-page:
---

Класс типов (_type class_) — это абстрактный параметризованный тип,
который позволяет добавлять новое поведение к любому закрытому типу данных без использования подтипов.
Если вы пришли с Java, то можно думать о классах типов как о чем-то вроде [`java.util.Comparator[T]`][comparator].

> В статье ["Type Classes as Objects and Implicits"][typeclasses-paper] (2010 г.) обсуждаются основные идеи,
> лежащие в основе классов типов в Scala.
> Несмотря на то, что в статье используется более старая версия Scala, идеи актуальны и по сей день.

Этот стиль программирования полезен во многих случаях, например:

- выражение того, как тип, которым вы не владеете, например, из стандартной или сторонней библиотеки, соответствует такому поведению
- добавление поведения к нескольким типам без введения отношений подтипов между этими типами (например, когда один расширяет другой)

Классы типов — это трейты с одним или несколькими параметрами,
реализации которых предоставляются в виде экземпляров `given` в Scala 3 или `implicit` значений в Scala 2.

## Пример

Например, `Show` - хорошо известный класс типов в Haskell, и в следующем коде показан один из способов его реализации в Scala.
Если предположить, что классы Scala не содержат метода `toString`, то можно определить класс типов `Show`,
чтобы добавить это поведение к любому типу, который вы хотите преобразовать в пользовательскую строку.

### Класс типов

Первым шагом в создании класса типов является объявление параметризованного trait, содержащего один или несколько абстрактных методов.
Поскольку `Showable` содержит только один метод с именем `show`, он записывается так:

{% tabs 'definition' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
// класс типов
trait Showable[A] {
def show(a: A): String
}
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
// класс типов
trait Showable[A]:
extension (a: A) def show: String
```

{% endtab %}
{% endtabs %}

Обратите внимание, что этот подход близок к обычному объектно-ориентированному подходу,
когда обычно trait `Show` определяется следующим образом:

{% tabs 'trait' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
// a trait
trait Show {
def show: String
}
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
// a trait
trait Show:
def show: String
```

{% endtab %}
{% endtabs %}

Следует отметить несколько важных моментов:

1. Классы типов, например, `Showable` принимают параметр типа `A`, чтобы указать, для какого типа мы предоставляем реализацию `show`;
в отличие от классических трейтов, наподобие `Show`.
2. Чтобы добавить функциональность `show` к определенному типу `A`, классический трейт требует наследования `A extends Show`,
в то время как для классов типов нам требуется реализация `Showable[A]`.
3. В Scala 3, чтобы разрешить один и тот же синтаксис вызова метода в обоих случаях `Showable`,
который имитирует синтаксис `Show`, мы определяем `Showable.show` как метод расширения.

### Реализация конкретных экземпляров

Следующий шаг — определить, какие классы `Showable` должны работать в вашем приложении, а затем реализовать для них это поведение.
Например, для реализации `Showable` следующего класса `Person`:

{% tabs 'person' %}
{% tab 'Scala 2 и 3' %}

```scala
case class Person(firstName: String, lastName: String)
```

{% endtab %}
{% endtabs %}

необходимо определить одно _каноническое значение_ типа `Showable[Person]`, т.е. экземпляр `Showable` для типа `Person`,
как показано в следующем примере кода:

{% tabs 'instance' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
implicit val showablePerson: Showable[Person] = new Showable[Person] {
def show(p: Person): String =
s"${p.firstName} ${p.lastName}"
}
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
given Showable[Person] with
extension (p: Person) def show: String =
s"${p.firstName} ${p.lastName}"
```

{% endtab %}
{% endtabs %}

### Использование класса типов

Теперь вы можете использовать этот класс типов следующим образом:

{% tabs 'usage' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
val person = Person("John", "Doe")
println(showablePerson.show(person))
```

Обратите внимание, что на практике классы типов обычно используются со значениями, тип которых неизвестен,
в отличие от type `Person`, как показано в следующем разделе.

{% endtab %}
{% tab 'Scala 3' %}

```scala
val person = Person("John", "Doe")
println(person.show)
```

{% endtab %}
{% endtabs %}

Опять же, если бы в Scala не было метода `toString`, доступного для каждого класса, вы могли бы использовать эту технику,
чтобы добавить поведение `Showable` к любому классу, который вы хотите преобразовать в `String`.

### Написание методов, использующих класс типов

Как и в случае с наследованием, вы можете определить методы, которые используют `Showable` в качестве параметра типа:

{% tabs 'method' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
def showAll[A](as: List[A])(implicit showable: Showable[A]): Unit =
as.foreach(a => println(showable.show(a)))

showAll(List(Person("Jane"), Person("Mary")))
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
def showAll[A: Showable](as: List[A]): Unit =
as.foreach(a => println(a.show))

showAll(List(Person("Jane"), Person("Mary")))
```

{% endtab %}
{% endtabs %}

### Класс типов с несколькими методами

Обратите внимание: если вы хотите создать класс типов с несколькими методами, исходный синтаксис выглядит следующим образом:

{% tabs 'multiple-methods' class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
trait HasLegs[A] {
def walk(a: A): Unit
def run(a: A): Unit
}
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
trait HasLegs[A]:
extension (a: A)
def walk(): Unit
def run(): Unit
```

{% endtab %}
{% endtabs %}

### Пример из реального мира

В качестве примера из реального мира, как классы типов используются в Scala 3,
см. обсуждение `CanEqual` в [разделе Multiversal Equality][multiversal].

[typeclasses-paper]: https://infoscience.epfl.ch/record/150280/files/TypeClasses.pdf

[typeclasses-chapter]: {% link _overviews/scala3-book/ca-type-classes.md %}
[comparator]: https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html
[multiversal]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}