const
для виджетовСегодня получил такой вопрос, хотел просто ответить коротко, но решил расширить тему и сделать небольшую статью для более полного объяснения.
Перед тем как говорить об этом, стоит вспомнить старый, но золотой принцип: виджеты в Flutter являются неизменяемыми объектами, они не являются настоящими представлениями (views). Виджеты представляют собой лишь конфигурационные данные.
Только поняв этот принцип и соединив его с глубинной неизменяемостью ключевого слова const
, можно лучше понять, почему в Flutter рекомендуется использование const
для виджетов.
final
и const
в DartДля начала давайте рассмотрим различия между final
и const
в Dart:
final
: переменная может быть присвоена значение только один раз, значение определяется во время выполнения программы.
const
: переменная должна быть компиляционной константой, значение известно до компиляции.
Хотя оба этих ключевых слова используются для создания неизменяемых значений, основное отличие заключается в том, что final
используется для значений, определяемых во время выполнения, а const
— для значений, известных до компиляции.
final
Конечно, final
также создаёт неизменяемое значение, но это значение может быть определено во время выполнения программы. Кроме того, final
позволяет использовать позднюю инициализацию (late initialization):```dartlate final String a;
void runResult() { final int result = doSomeThing(); }
То есть, `final` позволяет присваивать значения во время выполнения, после чего они становятся неизменяемыми. Это аналогично тому, как мы можем использовать `final` для создания неизменяемых переменных внутри конструктора виджета:
```dart
class MyHomePage extends StatelessWidget {
MyHomePage({super.key, this.title});
final String? title;
}
const
представляет собой более строгий тип неизменяемости, который определяется до компиляции. Это делает его глубоко неизменяемым, и таким образом он обеспечивает лучшую производительность, так как значения уже известны на этапе компиляции:
const String myConstant = 'Hello';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text(myConstant),
);
}
}
```Таким образом, использование ключевого слова `const` для виджетов в Flutter помогает улучшить производительность приложения, поскольку все необходимые данные уже известны на этапе компиляции. Константы типа `const` известны во время компиляции, поэтому они оцениваются всего один раз в процессе компиляции, что позволяет Dart-компилятору оптимизировать их использование, экономя память и сокращая время старта. Когда константы типа `const` используются в разных местах, Dart-компилятор выделяет место для них лишь однажды, а значение будет повторно использоваться в других местах, где она привязана. С этой точки зрения, **константы действительно могут повысить производительность и сэкономить память**. Давайте рассмотрим типичный пример объяснения "неизменяемости", как показано ниже:> Можно заметить, что список, объявленный через `const`, имеет внутренние элементы, которые определяются во время компиляции и не могут быть изменены. Кроме того, сам список является константой времени компиляции, а каждый его элемент также является константой времени компиляции.
```dart
const List<int> list = [0, 0, 0, 0, 0, 0];
list[2] = 3;
Что касается классов, то конструктор, объявленный через const
, требует использования ключевого слова final
для всех внутренних переменных, чтобы гарантировать, что объект является неизменяемым и передаваемым. Это обеспечивает целостность статических данных и гарантирует, что объект нельзя будет изменить после его создания.
class Test {
final int a;
const Test(this.a);
}
void runTest() {
const Test test = Test(0);
test.a = 100; /// Ошибка
}
Это выглядит знакомым? Да, это именно так — в Flutter такие свойства имеют виджеты. Когда конструктор виджета объявлен через const
, все его внутренние переменные должны быть объявлены через final
, иначе возникнет ошибка при компиляции.
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});
final String? title;
}
Без объявления
const
по умолчанию это будет просто предупреждение: Класс (или класс, от которого этот класс наследуется) помечен как «@immutable», но один или несколько его полей экземпляра не являются final.Кроме того, конструктор, объявленный через
const`, также оптимизируется во время компиляции для класса, как показано ниже:
test1
и test2
совпадаютtest3
и test4
совпадаютclass Test {
final int a;
final int b;
const Test(this.a, this.b);
}
void runTest() {
const Test test1 = Test(0, 0);
print("Хэш-код test1: ${test1.hashCode}");
const Test test2 = Test(0, 0);
print("Хэш-код test2: ${test2.hashCode}");
const Test test3 = Test(1, 1);
print("Хэш-код test3: ${test3.hashCode}");
const Test test4 = Test(1, 1);
print("Хэш-код test4: ${test4.hashCode}");
const Test test5 = Test(2, 2);
print("Хэш-код test5: ${test5.hashCode}");
}
Тогда вернёмся к первоначальному вопросу. Поскольку виджеты в Flutter не являются настоящими представлениями (Views), а представляют собой лишь конфигурационные файлы, за которыми скрываются реальные объекты Element и RenderObject, то использование ключевого слова const
для объявления этих "конфигураций" позволяет значительно повысить производительность и снизить потребление памяти.
Что же касается того, почему виджеты не считаются настоящими представлениями (Views), более подробно можно прочитать в моих предыдущих статьях. Здесь я приведу простой пример, который часто используется для демонстрации этой идеи:
// Пример кода textUseAll, если это было бы настоящим представлением (View),
// оно не могло бы одновременно использоваться несколькими местами.
```Для Flutter важно отметить, что **Flutter сильно зависит от конфигурационной информации виджетов дерева для отображения интерфейса пользователя. В процессе перестроения (rebuild) при встрече с виджетом, помеченным как const, Flutter распознает его как предварительно созданное и неизменяемое представление**, что позволяет повторно использовать существующие объекты вместо создания новых. Это помогает избежать ненужных вычислений и аллокаций объектов.
> Кроме того, как уже упоминалось ранее, const выполняет оптимизации во время компиляции, такие как предварительное выделение памяти и свертка констант, что позволяет создавать объекты быстрее и снижает количество вызовов сборщика мусора.
Кроме того, использование const для деревьев виджетов гарантирует, что перестроение происходит только тогда, когда фактические ссылки действительно меняются, тем самым уменьшая количество ненужных операций по созданию и перестроению виджетов.
Итак, не увеличивается ли ваш объём полезных знаний?
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )