Конструкторы

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

Конструктором является метод со специальным именем constructor. У данного метода можно не объявлять явно аргумент this, он будет неявно создан. Конструктор можно перегружать, правила перегрузки такие же, как и у других функций.

Конструктор имеет специальную секцию внутри себя - список инициализации полей. Список инициализации размещается перед телом {} конструктора, состоит он из пары () скобок и указания полей с инициализаторами, через запятую. В этом списке можно инициализировать поля структуры или класса. Поля, не имеющие инициализатора по умолчанию, imut поля, ссылочные поля должны быть инициализированы в этом списке.

Вызывается конструктор не как обычный метод, а с использованием инициализатора (). Конструктор без аргументов, называемый конструктором по умолчанию, может быть вызван неявно. Обратиться к конструктору явно можно только из unsafe блока.

Пример использования конструктора:

struct Vec
{
    i32 x;
    i32 y;

    fn constructor()
    ( x= 0, y= 0 )
    {}

    fn constructor( i32 in_x, i32 in_y )
    ( x= in_x, y= in_y )
    {}
}

fn Foo()
{
    var Vec v0(); // Явно зовём конструктор по умолчанию
    var Vec v1; // Неявно зовём конструктор по умолчанию
    var Vec v2( 5, -3 ); // Зовём конструктор с двумя аргументами
}

Влияние конструкторов

Конструктор, имеющий параметром неизменяемую ссылку типа той же структуры или того же класса, что и this, считается конструктором копирования. Данный конструктор может неявно вызываться компилятором в местах, где нужно сделать копию значения.

Структура, у которой существует явно заданный конструктор, кроме конструктора копирования, лишается возможности быть инициализированной с помощью почленного инициализатора. Инициализировать такую структуру можно будет только через конструктор.

Генерация конструкторов

Компилятор может сгенерировать конструкотр по умолчанию для структуры или класса, если этот конструктор не объявлен явно. Для этого все поля должны быть конструируемы по умолчанию а также не должно быть ссылочных полей.

Компилятор может сгенерировать конструктор копирования для структуры, если этот конструктор не объявлен явно. Для этого все поля (кроме ссылочных) должны иметь конструкторы копирования.

struct Vec
{
    i32 x= 0;
    i32 y= 0;
}

fn Foo()
{
    var Vec v0; // Позовётся сгенерированный конструктор по умолчанию
    var Vec v1(v0), v2= v0; // В обоих случаях позовётся сгенерированный конструктор копирования
}

Конструктор преобразования

Существует особый вид конструктора - конструктор преобразования. Он создан для того, чтобы можно было преобразовать значения какого-то типа в значения структуры/класса. Объявляется такой конструктор с использованием ключевого слова conversion_constructor в качестве имени. Данный конструктор, по очевидным причинам, должен иметь один аргумент (кроме this).

Конструктор преобразования можно использовать так же, как обычный конструктор. Кроме того, он может быть использован неявно, когда нужно преобразовать значение в нужный тип.

struct IntWrapper
{
    i32 x;
    fn conversion_constructor( i32 in_x ) ( x= in_x ) {}
}

fn Bar( IntWrapper iw );

fn Foo()
{
    var IntWrapper iw0(55); // Обычное использование конструктора.
    var IntWrapper iw1= 42; // Неявное приобразование при инициализации.
    Bar(66); // Неявное преобразование при вызове функции.
}