0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Scala имеет гибкую ООП-модель, которая состоит из трейтов, обжектов, классов и кейс-классов, то есть модель чем-то напоминает аналогичную в Java. Вот, например, объявления класса:</p>
1
<p>Scala имеет гибкую ООП-модель, которая состоит из трейтов, обжектов, классов и кейс-классов, то есть модель чем-то напоминает аналогичную в Java. Вот, например, объявления класса:</p>
2
class ClassName(field1: Type1, field2: Type2, … , fieldN: TypeN) { // class body }<p>Объявленный таким образом класс инстанцируется посредством конструкции new ClassName(field1, field2, … , fieldN). Параметры, которые вводятся в скобках после имени класса, - private-поля класса, но мы можем изменить область их видимости. К примеру, если нам надо обеспечить доступ на чтение извне, то перед именем поля следует поставить модификатор<em>val</em>. Если надо обеспечить запись и чтение - модификатор<em>var</em>. Классы в Scala являются ссылочными типами и наследуют базовый класс AnyRef (неявно). Таким образом, присваивание объекта с мутирующими (var) полями другой переменной лишь копирует ссылку.</p>
2
class ClassName(field1: Type1, field2: Type2, … , fieldN: TypeN) { // class body }<p>Объявленный таким образом класс инстанцируется посредством конструкции new ClassName(field1, field2, … , fieldN). Параметры, которые вводятся в скобках после имени класса, - private-поля класса, но мы можем изменить область их видимости. К примеру, если нам надо обеспечить доступ на чтение извне, то перед именем поля следует поставить модификатор<em>val</em>. Если надо обеспечить запись и чтение - модификатор<em>var</em>. Классы в Scala являются ссылочными типами и наследуют базовый класс AnyRef (неявно). Таким образом, присваивание объекта с мутирующими (var) полями другой переменной лишь копирует ссылку.</p>
3
<p>Внутри класса мы можем вводить многие вложенные структуры, необходимые для внутреннего использования. При этом по умолчанию все переменные, методы и постоянные, которые объявлены в теле класса, являются публичными. Мы можем их защитить посредством модификаторов private и protected. Что касается вложенных классов, то они извне недоступны.</p>
3
<p>Внутри класса мы можем вводить многие вложенные структуры, необходимые для внутреннего использования. При этом по умолчанию все переменные, методы и постоянные, которые объявлены в теле класса, являются публичными. Мы можем их защитить посредством модификаторов private и protected. Что касается вложенных классов, то они извне недоступны.</p>
4
<p>Вторая ООП-сущность -<strong>trait</strong>. Trait, в отличие от класса, не может иметь конструктора, следовательно, не может быть инстанцирован. Вдобавок к этому, он способен содержать абстрактные методы, тогда как класс - лишь в том случае, если помечен модификатором abstract.</p>
4
<p>Вторая ООП-сущность -<strong>trait</strong>. Trait, в отличие от класса, не может иметь конструктора, следовательно, не может быть инстанцирован. Вдобавок к этому, он способен содержать абстрактные методы, тогда как класс - лишь в том случае, если помечен модификатором abstract.</p>
5
<p>Рассмотрим синтаксис трейта:</p>
5
<p>Рассмотрим синтаксис трейта:</p>
6
<p>Существует ещё одна ООП-сущность, которую мы рассматривали<a>в этой</a>статье. Речь идёт об<strong>object</strong>. Его отличительная черта - наличие единственного экземпляра, создаваемого автоматически, то есть он является синглтоном. Лишь object может быть точкой входа в программу. Вдобавок к этому, можно импортировать его вложенные типы, значения и методы в область видимости другого файла. Всё это даёт возможность применять object в качестве средства структурной организации программы, что в свою очередь даёт возможность группировать статические методы и константы.</p>
6
<p>Существует ещё одна ООП-сущность, которую мы рассматривали<a>в этой</a>статье. Речь идёт об<strong>object</strong>. Его отличительная черта - наличие единственного экземпляра, создаваемого автоматически, то есть он является синглтоном. Лишь object может быть точкой входа в программу. Вдобавок к этому, можно импортировать его вложенные типы, значения и методы в область видимости другого файла. Всё это даёт возможность применять object в качестве средства структурной организации программы, что в свою очередь даёт возможность группировать статические методы и константы.</p>
7
<h2>Особенности наследования в Scala</h2>
7
<h2>Особенности наследования в Scala</h2>
8
<p>Особенностей несколько: во-первых, почти всё можно наследовать от нескольких trait посредством синтаксиса<em>extends trait1 with trait2 with trait3 ... with traitN</em>.</p>
8
<p>Особенностей несколько: во-первых, почти всё можно наследовать от нескольких trait посредством синтаксиса<em>extends trait1 with trait2 with trait3 ... with traitN</em>.</p>
9
object HelloWorld extends App<p>В нашем случае App является предопределённым трейтом, оборачивающим содержимое внутрь метода main.</p>
9
object HelloWorld extends App<p>В нашем случае App является предопределённым трейтом, оборачивающим содержимое внутрь метода main.</p>
10
<p>Зачем нам нужен синтаксис extends … with … with …? Может, мы можем обойтись одним ключевым словом? К сожалению, не можем. Если же мы разрешим множественное наследование, то столкнёмся с проблемой<strong>ромбовидного наследования</strong>. В языке программирования Scala данная проблема решается путём определения главного трейта, реализация которого и наследуется. Речь идёт о трейте, который идёт первым после extends (кстати, это может быть и не трейт вовсе, а класс либо абстрактный класс).</p>
10
<p>Зачем нам нужен синтаксис extends … with … with …? Может, мы можем обойтись одним ключевым словом? К сожалению, не можем. Если же мы разрешим множественное наследование, то столкнёмся с проблемой<strong>ромбовидного наследования</strong>. В языке программирования Scala данная проблема решается путём определения главного трейта, реализация которого и наследуется. Речь идёт о трейте, который идёт первым после extends (кстати, это может быть и не трейт вовсе, а класс либо абстрактный класс).</p>
11
<p>Также мы не можем наследовать типы от объекта.</p>
11
<p>Также мы не можем наследовать типы от объекта.</p>
12
<p>По правде говоря, у нас есть возможность создать анонимный класс-наследник трейта и реализовать все его абстрактные методы с помощью функционала анонимных классов, а потом создать его экземпляр:</p>
12
<p>По правде говоря, у нас есть возможность создать анонимный класс-наследник трейта и реализовать все его абстрактные методы с помощью функционала анонимных классов, а потом создать его экземпляр:</p>
13
trait T {} val t = new T { // имплементация абстрактных методов }<p>Однако писать данный код бывает весьма громоздким занятием. Для этого в Scala есть<em>companion object</em>- объекты-компаньоны. Для них не существует специального ключевого слова, поэтому для их определения надо создать в файле с классом либо трейтом object с тем же именем, что и у класса. У такого обжекта-компаньона вы сможете определить метод apply:</p>
13
trait T {} val t = new T { // имплементация абстрактных методов }<p>Однако писать данный код бывает весьма громоздким занятием. Для этого в Scala есть<em>companion object</em>- объекты-компаньоны. Для них не существует специального ключевого слова, поэтому для их определения надо создать в файле с классом либо трейтом object с тем же именем, что и у класса. У такого обжекта-компаньона вы сможете определить метод apply:</p>
14
trait Foo { def bar: Int } object Foo { def apply(int: Int) = new Foo { override def bar = int } }<p>Тогда появится возможность создавать "экземпляры" трейта посредством синтаксиса Foo.apply(1).</p>
14
trait Foo { def bar: Int } object Foo { def apply(int: Int) = new Foo { override def bar = int } }<p>Тогда появится возможность создавать "экземпляры" трейта посредством синтаксиса Foo.apply(1).</p>
15
<p>Так как этот код громоздкий, специально для метода apply разрешили не писать его название. Данная "магия" работает для всего, что называют apply в любой сущности. Вот, как это выглядит:</p>
15
<p>Так как этот код громоздкий, специально для метода apply разрешили не писать его название. Данная "магия" работает для всего, что называют apply в любой сущности. Вот, как это выглядит:</p>
16
<p>То же самое мы можем делать и с классами. Также следует заметить, что семантика метода apply может существенно отличаться от вышеприведённого примера, ведь никто не ограничивает в том, что именно будет делать этот метод. Данная особенность активно применяется и в стандартных, и в сторонних библиотеках.</p>
16
<p>То же самое мы можем делать и с классами. Также следует заметить, что семантика метода apply может существенно отличаться от вышеприведённого примера, ведь никто не ограничивает в том, что именно будет делать этот метод. Данная особенность активно применяется и в стандартных, и в сторонних библиотеках.</p>
17
<p><em>Материал написан на основании статьи Ивана Камышана"Основы функционального программирования с примерами на Scala - часть 2".</em></p>
17
<p><em>Материал написан на основании статьи Ивана Камышана"Основы функционального программирования с примерами на Scala - часть 2".</em></p>
18
18