В данном разделе будут рассмотрены функции. Методы будут раccмотрены только в теме объявлений входных аргументов.
Важное замечание!
В языке программирования Dart примитивные типы int, double, bool и String передаются по значению, остальные типы - передаются по ссылке!
Входные аргументы функции Dart подразделяются на:
Самыми простыми в понимании являются позиционное аргументы, так как последовательность передаваемых на вход функций переменных, должна соответствовать последовательности и типу объявленных в функции аргументов:
void myFunction(String name, int date, String monthName) {
print('$name родился $date $monthName!');
}
void main(List<String> arguments) {
myFunction('Александр', 10, 'сентября');
}
// будет напечатано: Александр родился 10 сентября!
Для объявления того, что на вход функции аргументы передаются именованным образом необходимо обернуть их в фигурные скобки «{ }». После чего, в момент вызова функции явно указать какому именованному аргументу какое значение передается. Если тип объявляемого аргумента null-safety, т.е. не может хранить значение null, то перед объявляемым аргументом используйте ключевое слово required.
Если же значение передаваемого аргумента может хранить значение null, то после указания его типа нужно добавить символ ? и предусмотреть проверку на null, который может передаться в двух случаях:
void myFunction({
String? name,
required int date,
required String monthName,
}) {
if (name != null) {
return '$name родился $date $monthName!';
}
return 'Не установлено имя новорожденного!';
}
void main(List<String> arguments) {
myFunction(date: 10, name: 'Александр', monthName: 'сентября',);
myFunction(date: 10, monthName: 'сентября',);
}
// будет напечатано: Александр родился 10 сентября!
// будет напечатано: Не установлено имя новорожденного!
Значения могут передаваться в произвольной последовательности, так как мы явно указываем какому из аргументов функции будет соответствовать то или иное значение.
Когда мы указываем, что именованный аргумент может принимать значение null, он становится необязательным при вызове функции. Но когда, кровь из носу, запрещено давать такие вольности разработчику, который будет использовать ваш код – нужно пометить такой именованный аргумент, как required. Тогда у него не останется вариантов, кроме как самому передать такому именованному аргументу вызываемой функции null.
Для того, чтобы указать необязательные аргументы при их позиционном размещении, нужно обернуть их в квадратные скобки [ ]:
String myFunction(String name, int date, [String? monthName]) {
if (monthName != null) {
return '$name родился $date $monthName!';
}
return '$date числа, неустановленного месяца, родился $name!';
}
void main(List<String> arguments) {
print(myFunction('Александр', 20));
print(myFunction('Александр', 20, 'мая'));
}
// будет напечатано: 20 числа неустановленного месяца родился Александр!
// будет напечатано: Александр родился 20 мая!
Когда мы объявляем необязательные позиционные или именованные аргументы, они по умолчанию инициализируются значением null (когда при вызове функции им не задается отличное от null значение). Для того, чтобы присвоим им значение по умолчанию, отличное от null, после объявления имени аргумента нужно добавить оператор присваивание и само значение, которое будет использоваться в коде функции всякий раз, пока явно не передастся другое значение. При этом не имеет значения, тип объявляемого аргумента – null-safety или нет:
String myFunction(
String name, [
int? date = 10,
String monthName = 'июля',
]) {
return '$name родился $date $monthName!';
}
void main(List<String> arguments) {
print(myFunction('Александр'));
print(myFunction('Александр', 24));
print(myFunction('Александр', 20, 'мая'));
}
// будет напечатано: Александр родился 10 июля!
// будет напечатано: Александр родился 24 июля!
// будет напечатано: Александр родился 20 мая!
Чтобы ввести значение по умолчанию для именованных аргументов, достаточно просто присвоить ему значение и не использовать ключевое слово required. К расположению значений по умолчанию для такого типа аргументов требований нет, но лучше придерживаться устоявшейся традиции и объявлять их в конце:
String myFunction({
required String name,
required String monthName,
int date = 10,
}) {
return '$name родился $date $monthName!';
}
void main(List<String> arguments) {
print(myFunction(name: 'Александр', monthName: 'мая'));
print(myFunction(
date: 14,
name: 'Александр',
monthName: 'мая',
));
}
// будет напечатано: Александр родился 10 мая!
// будет напечатано: Александр родился 14 мая!
int addFunc(int a, int b) {
return a + b;
}
String seasonFunc(int month) {
return switch (month) {
== 12 || > 0 && < 3 => 'Зима',
>= 3 && < 6 => 'Весна',
>= 6 && < 9 => 'Лето',
>= 9 && < 12 => 'Осень',
_ => "Хрень в аргументах!",
};
}
String myStrFunc(
String prefix,
int month,
String Function(int) func,
) {
return prefix + ': ' + func(month);
}
int subFunc(
int a,
int b, {
int c = 10,
int Function(int, int) func = addFunc,
}) {
return c - func(a, b);
}
void main() {
var season = seasonFunc; // 1. Пример присвоение функции переменной
print(myStrFunc('Сезон', 12, season)); // 2. Пример использовании функции как аргумента
print(myStrFunc("Сезон", 0, season));
print(subFunc(3, 7));
print(subFunc(2, 4, c: 2));
print(subFunc(2, 4, c: 2, func: (int a, int b) { // 3. Пример использовании анонимной функции (лямбды) как аргумента
return a * b;
}));
}
Результат работы будет следующий:
Сезон: Зима Сезон: Хрень в аргументах! 0 -4 -6Еще один пример:
int sub(
int a,
int b, {
int c = 10,
int Function(int, int)? func,
}) {
if (func == null) {
return 0;
}
return c - func(a, b);
}
void main() {
var a = 13, b = 12;
print(sub(
2,
4,
c: 2,
func: a < b
? (int a, int b) {
return a * b;
}
: (int a, int b) {
return a - b;
},
));
}
Вывод:
4
typedef TypeMyMap = Map<String, Map<(int, List<int>), int>>; // 1. Алиас для сложного типа
typedef TypeMyMapFunc = int Function(TypeMyMap)?; // 2. Алиас для функции со сложным типом аргумента
int myFunc(TypeMyMap data) {
var sum = 0.0;
for (var MapEntry(:value) in data.entries) {
for (var MapEntry(key: recKey, value: recValue) in value.entries) {
var (int a, List<int> b) = recKey;
sum += (a * b.reduce((value, element) => value + element)) / recValue;
}
}
return sum.floor();
}
int add(
int a,
TypeMyMap data, {
TypeMyMapFunc func,
}) {
if (func == null) {
return 0;
}
return a + func(data);
}
void main() {
TypeMyMap map = {
'a': {
(1, [1, 2, 3]): 100,
(2, [2, -4, 9]): -98,
(3, [3, 4, 5]): 3,
},
'b': {
(10, [1, 0, 3]): 100,
(20, [6, -4, 2]): -98,
(30, [-3, 4, -5]): 3,
}
};
print(add(22, map, func: myFunc));
}
Будет напечатано:
-7
void main(List<String> arguments) {
var myList = ['Привет!', 'Я', '-', 'анонимная', 'функция!'];
myList.forEach((item) {
print( 'По индексу ${myList.indexOf(item)} хранится значение => $item' );
}
);
}
Будет напечатано:
По индексу 0 хранится значение => Привет! По индексу 1 хранится значение => Я По индексу 2 хранится значение => - По индексу 3 хранится значение => анонимная По индексу 4 хранится значение => функция!В данном примере анонимная функция имеет следующую реализацию:
(item) { // блок с входными аргументами, аргументы могут отсутствовать
// блок тела функции
}
int add(int a, int b) => a + b;
void main(List<String> arguments) {
print(add(1,2));
}
Будет напечатано:
3
Тем не менее, мы можем переписать пример выше, где возвращаемое будет просто игнорироваться:Важное замечание!
У стрелочных функций есть особенность - по умолчанию они всегда возвращают значение, то есть оператор return в этих функциях не используется, но его наличие подразумевается.
void main(List<String> arguments) {
var myList = ['Привет!', 'Я', '-', 'анонимная', 'функция!'];
myList.forEach((item) => print( 'По индексу ${myList.indexOf(item)} хранится значение => $item' ));
}
Вывод в консоль будет аналогичен:
По индексу 0 хранится значение => Привет! По индексу 1 хранится значение => Я По индексу 2 хранится значение => - По индексу 3 хранится значение => анонимная По индексу 4 хранится значение => функция!