Инициализация

Каждая переменная или поле структуры/класса должны быть инициализированы, явно или неявно. Отсутствие инициализации невозможно в safe коде, компилятор следит за тем, чтобы всё было инициализировано.

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

Инициализация выражением

Самая простая инициализация. Выражение помещается после = указанного для инициализируемой переменной.

var i32 x= 0;
var f32 y= 1.0f - 72.5f / 2.0f;

В комбинированных инициализаторах = отсутствует, инициализация выражением происходит при встрече данного выражения.

Инициализация последовательностью

Используется для инициализации массивов и кортежей. Состоит из перечисления инициализаторов через запятую внутри [] скобок. Количество элементов в инициализаторе должно совпадать с количеством элементов в массиве/кортеже.

var [ i32, 2 ] arr0[ 0, 1, 100 ]; // Инициализация массива
var [ f32, 3 ] arr1[ 0.0f, -5.0f, 44.4f ]; // Инициализация массива
var tup[ i32, bool ] tup0[ 5, false ]; // Инициализация кортежа
var [ [ i32, 2 ], 3 ] arr2[ [ 5, 7 ], [ 50, 70 ], [ 500, 700 ] ]; // Инициализация двумерного массива
var tup[ f32, [ i32, 3 ] ] tup1[ 0.0f, [ 0, 0, 0 ] ]; // Инициализация кортежа с массивом внутри

Инициализация конструктором

Используется для инициализации структур и классов, у которых есть конструкторы. Состоит из () скобок со списком аргументов конструктора внутри.

struct S
{
    fn constructor(){}
    fn constructor(i32 in_x, i32 in_y) (x= in_x, y= in_y) {}
    i32 x= 0;
    i32 y= 0;
}

fn Foo()
{
    var S s0(); // Вызов конструктора с нулём аргументов
    var S s1( 5, 7 ); // Вызов конструктора с двумя аргументами
    var [ S, 2 ] arr0[ (), ( 99, 55 ) ]; // Вызов разных конструкторов для структур-членов массива
}

Для фундаментальных типов инициализация конструктором позволяет произвести преобразование из одного типа в другой или же просто сделать копию.

var i32 x= 0, x_copy(x);
var f32 y(x); // преобразование i32 -> f32
var f64 z(y), w(x_copy); // преобразования f32 -> f64 и i32 -> f64
var u16 cc("B"c8); // преобразование char8 -> u16
var char32 cccc(66); // преобразование i32 -> char32
var u16 short_int(574);
var i64 long_signed_int(short_int); // преобразование u16 -> i64

Инициализация конструктором позволяет сделать копию для переменных типов массивов и кортежей.

var [i32, 2] i0 = zero_init, i1(i0);
var tup[bool, f32] t0[true, 14.5f], t1(t0);

Почленная инициализация структур

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

struct S
{
    i32 x;
    i32 y;
    i32 z= 0;
}

fn Foo()
{
    var S s0{ .x= 0, .y= 0, .z= 0 }; // Инициализируем все поля по порядку
    var S s1{ .y= 1, .x= 0 }; // Порядок можно менять. Поля, которые имеют инициализаторы по умолчанию, можно не указывать
    var tup[ S ] t[ { .z= 0, .x= 2, .y= 2 } ];
}

Данный инициализатор можно использовать также в контексте выражения для создания временных значений типов структур.

struct S{ i32 x; i32 y; }
fn Bar(S s);
fn Foo()
{
    Bar( S{ .x= 42, .y= 24 } ); // Создаём временное значение типа "S", инициализируя его поля, после чего передаём его в функцию.
}

Пустая инициализация

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

struct S
{
    fn constructor() (x= 0, y= 0) {} // Конструктор по умолчанию

    i32 x;
    i32 y;
}

fn Foo()
{
    var S s; // Будет вызван конструктор по умолчанию
    var [ S, 8 ] arr; // Будет вызван конструктор по умолчанию для всех элементов массива
}

Зануляющая инициализация

Используется для инициализации нулём для числовых типов, false для bool, первым значением для перечислений, \0 для символьных типов, нулевым указателем для указателей на функции. Её нельзя применять к классам. К структурам её можно применять только если структура не имеет явных конструкторов, кроме конструктора копирования. Зануляющая инициализация указывается с использованием ключевого слова zero_init.

struct S
{
    i32 x;
    i32 y;
}

enum E{ A, B, C, }

fn Foo()
{
    var i32 x= zero_init;
    var S s0= zero_init; // Зануляем всю структуру
    var S s1{ .x= 4, .y= zero_init }; // Зануляем одно из полей структуры
    var [ f32, 128 ] arr0= zero_init; // Зануляем весь массив чисел
    var [ S, 3 ] arr1= zero_init; // Зануляем весь массив структур
    var [ S, 2 ] arr2[ { .x= 1, .y= 1 }, zero_init ]; // Зануляем только одну структуру в массиве
    var tup[ E, bool, i32, i64, f64 ] t= zero_init; // Зануляем весь кортеж
}

Неинициализирующая инициализация

Позволяет совсем не инициализировать значение. Позволена она только в unsafe блоках. Используйте её только если очень надо и если есть уверенность, что значение будет позже инициализировано, как надо.

fn Foo()
{
    unsafe
    {
        var i32 x= uninitialized;
    }
}

Список инициализации конструктора

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

struct S
{
    fn constructor()
    ( y= z + 1, x= y / 2 ) // "z" инициализируется в самом начале, неявно, затем инициализируется "y" с использованием значения "z" и "x" с использованием инициализированного ранее значения "x"
    {}

    i32 x;
    i32 y;
    i32 z= 0;
}

Собственные инициализаторы полей

Поля структур и классов могут иметь собственные инициализаторы, указанные при объявлении поля. Поле будет инициализировано этим инициализатором, если для него не указан никакой другой инициализатор.

struct A
{
    // Для данной структуры будет сгенерирован конструктор по умолчанию, т. к. все поля есть чем инициализировать
    i32 x= 100;
}

struct Vec
{
   fn constructor() () {} // Поля инициализируются по умолчанию
   fn constructor(i32 in_x, i32 in_y) (x= in_x, y= in_y) {} // Поля инициализируются указанными значениями, инициализатор по умолчанию не используется
   i32 x= 0;
   i32 y= 0;
}

struct SimpleVec
{
    A a; // Поле имеет инициализатор по умолчанию, т. к. "A" имеет конструктор по умолчанию
    i32 x= 0;
    i32 y= 0;
}

fn Foo()
{
    var A a; // Будет вызыван сгенерированный конструктор по умолчанию. Сгенерируется он потому, что все поля имеют инициализаторы.
    var Vec v0(), v1, v2( 10, -5 ); // В первых двух случаях поля будут инициализированы по умолчанию, в третьем - указанными в конструкторе значениями.
    var SimpleVec v3{}; // В инициализаторе структуре опущенные поля инициализируются значениями по умолчанию
}