Функции¶
Ü поддерживает свободные функции. Функции принимают от нуля и более аргументов и могут возвращать значение.
Примеры объявлений функций:
fn Add( i32 x, i32 y ) : i32; // Функция принимает два аргумента типов "i32" и возвращает значение типа "i32".
fn Sleep( f32 sec ); // Функция принимает один аргумент типа "f32" и не возвращает значения.
fn GetPi() : f64; // Функция не принимает аргументов и возвращает значение типа "f64".
fn Max( i64& x, i64& y ) : i64&; // Функция принимает два аргумента типов "i64" по ссылке и возвращает ссылку того же типа.
Аргументы¶
Функции могут принимать аргументы-значения и ссылочные аргументы.
Ссылочные аргументы объявляются с использованием &
после имени типа аргумента.
Аргументы могут иметь модификаторы изменяемости mut
или imut
, указываемые после имени типа или после &
(для ссылочных аргументов).
Если модификатор изменяемости не указан, неявно будет применён модификатор imut
.
Для ссылочных аргументов модификаторы изменяемости имеют значения для вызываемого кода. В функцию, принимающую изменяемую ссылку, нельзя передать неизменяемую переменную. Для аргументов значений же модификатор изменяемости влияет только на тело функции, неизменяемый аргумент-значение нельзя будет изменить в теле.
Примеры аргументов:
fn Add( i32 imut x, i32 y ) : i32; // Неизменяемые аргументы-значения. Второй аргумент будет неизменяемым, т. к. к нему применён модификатор по умолчанию "imut"
fn Inc( u32 &mut x ); // Изменяемый ссылочный аргумент
fn GetLength( ust::string8 &imut str ) : size_type; // Неизменяемый ссылочный аргумент
fn GetNumZeros( ust::string8 & str ) : size_type; // Неизменяемый ссылочный аргумент, т. к. к нему применён модификатор по умолчанию "imut"
Возвращаемое значение¶
Функция может не возвращать значений. Для этого можно или не указать тип возвращаемого значения, или указать тип void
:
fn Sleep( f32 sec );
fn USleep( u64 ns ) : void;
Функция может возвращать значение. Для этого надо указать тип значения:
fn Add( i32 x, i32 y ) : i32; // тип возвращаемого значения - "i32"
Функция может возвращать ссылочное значение - изменяемое или неизменяемое. Для этого надо указать &
после типа возвращаемого значения.
После него можно опционально указать модификатор изменяемости mut
или imut
.
Если модификатор изменяемости не указан, неявно будет применён модификатор imut
.
fn Max( i64& x, i64& y ) : i64 &imut; // Функция вернёт неизменяемую ссылку типа "i64"
fn Max( u64& x, u64& y ) : u64 &; // Функция вернёт неизменяемую ссылку типа "u64", модификатор "imut" применён неявно
fn Max( u64 &mut x, u64 &mut y ) : i64 &mut; // Функция вернёт изменяемую ссылку типа "u64"
Перегрузка функций¶
Возможно объявить более одной функции с одним и тем же именем в одном пространстве имён. Но у всех одноимённых функций должны различаться параметры - числом, типом, изменяемостью (для ссылочных параметров).
fn Foo();
fn Foo(i32 x); // Ок, перегрузка с другим количеством параметров
fn Foo(f32 &imut x); // Ок, перегрузка с другим типом параметра
fn Foo(f32 &mut x); // Ок, перегрузка с с отличной изменяемостью параметра
Если у функций различается только что-то кроме параметров (возвращаемое значение, модификатор unsafe
), то перегрузка невозможна.
Также невозможна перегрузка с различием только в изменяемости параметров-значений или перегрузка неизменяемого параметра по модификатору ссылочности.
fn Foo() : i32;
fn Foo() unsafe : f32; // Ошибка, перегрузка невозможна - сигнатура функций одинакова
fn Bar(i32 mut x);
fn Bar(i32 imut x); // Ошибка, перегрузка невозможна - различается только изменяемость параметра-значения
fn Baz(i32 imut x);
fn Baz(i32 &imut x); // Ошибка, перегрузка невозможна - различается только ссылочный модификатор неизменяемого параметра
Прототипы и реализации¶
Объявление функции, оканчивающееся на ;
означает, что объявлен лишь прототип функции, если же после объявления функции следует блок её тела, обрамлённый в {}
, то это объявление реализации.
// объявили прототип
fn Add( i32 x, i32 y ) : i32;
// позже объявили реализацию функции
fn Add( i32 x, i32 y ) : i32
{
return x + y;
}
Вывод типа возвращаемого значения¶
Вместо типа возвращаемого значения функции можно указать ключевое слово auto
.
В этом случае тип возвращаемого значения выведется автоматически из оператора return
.
fn Div( i32 x, i32 y ) : auto
{
return x / y; // Тип будет "i32"
}
fn Abs( f32 x ) : auto
{
// Во всех операторах "return" тип - "f32"
if( x >= 0.0f ) { return x; }
return -x;
}
Функции с выводом типа возвращаемого значения имеют ряд ограничений:
- Они должны иметь тело
- Они не могут рекурсивно звать сами себя
- Они не могут быть членами структур или классов
Условное наличие функции¶
Иногда необходимо, чтобы функция отсутствовала, в зависимости от какого-либо условия.
Особенно это может быть полезно в шаблонном коде. Для этого в Ü существует специальная конструкция - enable_if
.
Эта конструкция может быть указана после fn
, опциональных constexpr
, virtual
, nomangle
в объявлении функции.
После этого указывается выражение, в ()
скобках. Выражение должно быть константой времени компиляции и иметь тип bool
.
Если выражение ложно - функция построена не будет, дальнейший её заголовок и тело не будут обрабатываться.
auto constexpr is_32bit = typeinfo</size_type/>.size_of == 4s;
// Функция будет существовать только на 32-битной платформе
fn enable_if( is_32bit ) Bar();
fn Foo()
{
Bar(); // На 64-битной платформе будет ошибка компиляции - функция не найдена.
}