Список аргументов переменной длины

Vala поддерживает список аргументов переменной длины в стиле С. Они объявляются с помощью многоточия в заголовке метода. Метод с переменным числом аргументов должен иметь хотя бы один фиксированный параметр:

void method_with_varargs(int x, ...) {
    var l = va_list();
    string s = l.arg();
    int i = l.arg();
    stdout.printf("%s: %d\n", s, i);
}

Здесь х - фиксированный аргумент, нужен чтобы метод удовлетворял требованиям. Вы получаете список аргументов с помощью va_list(). Затем вы можете получить параметры один за другим с помощью обобщенного метода arg<T>(), где Т - это ожидаемый тип аргументов. Если тип, как в данном случае, легко может быть выяснен, то он будет выведен автоматически, и вам нужно вызывать лишь arg() без указания обобщенного типа.

Следующий пример делает разбор парных аргументов, имеющих типы string и double:

void method_with_varargs(int fixed, ...) {
    var l = va_list();
    while (true) {
        string? key = l.arg();
        if (key == null) {
            break;  // конец списка
        }
        double val = l.arg();
        stdout.printf("%s: %g\n", key, val);
    }
}

void main() {
    method_with_varargs(42, "foo", 0.75, "bar", 0.25, "baz", 0.32);
}

Здесь проводится проверка на null для определения конца списка аргументов. Vala неявно передает методу нулевой элемент в конце списка аргументов, если они имеют переменную длину.

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

Общий паттерн при работе с аргументами переменного числа - это указывать аргументы парами строка-значение, обычно используются пары gobject свойство - значение. В таком случае вы можете написать как свойство : значение, т.е.:

actor.animate (AnimationMode.EASE_OUT_BOUNCE, 3000, x: 100.0, y: 200.0, rotation_angle_z: 500.0, opacity: 0);

эквивалентен строке

actor.animate (AnimationMode.EASE_OUT_BOUNCE, 3000, "x", 100.0, "y", 200.0, "rotation-angle-z", 500.0, "opacity", 0);

Last updated