Мы можем вернуть из функции несколько значений. Для этого мы возвращаем кортеж.
fn func() -> (let a,b)
{
return (10, "test");
}
let (a,b) = func();
print(a) // 10
print(b) // "test"
Возможность выбросить исключения должна быть описана явно если функция бросает исключения.
import exc::wrong_arg;
fn deiv(let a : num, let b : num) -> throws(exc::wrong_arg), (let num)
{
if (b == 0)
throw exc::wrong_arg("Wrong arg, b == 0");
return a / b;
}
В скобках throws перечислены возможные виды исключений.
Если оставить поле пустым - функция возвращает любое значение.
Если написать throws(false) функция гарантирует что не вернёт исключения.
В таком случае мы должны внутри неё не вызывать функций которые могут
вернуть исключения или обрабатывать их.
Исключения тоже можно проверять на корректность как и возвращаемое значение.
fn test() -> throws({@.line == 10})
{
}
Ошибка могла произойти в строке 10 и только там. Если во время проверки исключения мы получили ошибку, будет выброшено ещё одно исключение.
fn func() -> throw::auto
{
if (int(input()) > 10)
throw (exc::overflow, "more than 10");
else
return "less than 10";
}
Мы запрашиваем ввод. Если введено число больше 10 то
выбрасывается исключение type::ex::overflow и к нему
прикрепляется результат функции "more than 10"
Иначе мы возвращаемся из функции штатно и возвращаем
"less than 10"
fn nodiscard func()
{
// ...
return exc::overflow;
}
В данном случае мы возвращаем ошибку через значение функции.
Мы можем поймать такую ошибку как и через оператор throw
Спецификатор nodiscard говорит, что мы не можем проигнорировать
возвращаемое значение.
let a : type::res = try func();
match(a.ex)
{
ex::ok => { print("Ok"); print(a.res); }
ex::overflow => { print("Overflow"); }
default => { throw; }
}
Мы пробуем вызвать функцию func и получаем в
объект типа type::res.
У этого объекта есть 2 поля - res и ex.
Поле res хранит то, что вернула функция,
а поле ex исключение или код ошибки.
Если мы дошли до ex::default мы не отловили никаким
из предыдущих пунктов ошибки. Мы можем переслать
исключение дальше.
let a : type::res = try{
let a : int = 10;
let b = func(a);
}
match(a.ex)
{
ex::ok => { print("Ok"); }
@default => { print(
f"Except: {res.ex.what} Line: {res.ex.line}"
); }
@finally => { /* do smth */ }
}
Мы вызываем блок кода, далее мы сохраняем первое встречное
исключение. Далее мы проверяем - что мы получили,
или ex::ok вывод по умолчанию, если мы не встретили никаких
ошибок.
Если мы отловили какую-то ошибку - мы напечатаем имя исключения
и строку где она произошла.
Самым последним исполнится блок ex::finally
Заход в этот блок выполняется всегда после работы кода до него,
даже если мы вернулись return.
match((try func()).ex)
{
ex::ok => print(f"ok {@.res}"); // @ обозначает анонимный
// объект в скобках конструкции
@default => print("not ok");
}