Ответ
Extension-методы (расширения) в Dart — это мощный механизм, позволяющий добавлять новую функциональность к существующим классам, даже к тем, исходный код которых вы не можете изменить (например, классы из стандартной библиотеки или внешних пакетов). Это делается без создания подкласса и без использования утилитарных классов.
Базовый синтаксис:
extension MyStringExtensions on String {
// Добавляем метод capitalize() ко всем строкам
String capitalize() {
if (isEmpty) return this;
return '${this[0].toUpperCase()}${substring(1).toLowerCase()}';
}
// Добавляем геттер
bool get isPalindrome => reversed == this;
}
void main() {
print('dart'.capitalize()); // Вывод: Dart
print('racecar'.isPalindrome); // Вывод: true
}
Практическое применение во Flutter-разработке:
-
Упрощение работы с контекстом:
extension ContextExtensions on BuildContext { // Быстрое получение размеров экрана Size get screenSize => MediaQuery.of(this).size; double get screenWidth => screenSize.width; double get screenHeight => screenSize.height; // Упрощённый вызов навигации void popToRoot() => Navigator.of(this).popUntil((route) => route.isFirst); } // Использование в виджете @override Widget build(BuildContext context) { if (context.screenWidth > 600) { return _buildTabletLayout(); } return _buildMobileLayout(); } -
Расширение встроенных типов для предметной области:
extension DateTimeExtensions on DateTime { // Форматирование даты для отображения в UI String toDisplayFormat() { return DateFormat('dd.MM.yyyy HH:mm').format(this); } // Проверка, является ли дата сегодняшним днём bool get isToday { final now = DateTime.now(); return year == now.year && month == now.month && day == now.day; } } // Использование Text(DateTime.now().toDisplayFormat()); -
Добавление вспомогательных методов к коллекциям:
extension ListExtensions<T> on List<T> { // Безопасное получение элемента или null T? elementAtOrNull(int index) => (index >= 0 && index < length) ? this[index] : null; // Разделение списка на подсписки фиксированного размера (чанки) List<List<T>> chunk(int size) { return [ for (var i = 0; i < length; i += size) sublist(i, i + size > length ? length : i + size), ]; } }
Важные ограничения и особенности:
- Расширения не могут добавлять поля (переменные экземпляра) в класс, только методы и геттеры/сеттеры.
- Они работают на этапе компиляции и не влияют на производительность во время выполнения.
- Имя расширения (например,
MyStringExtensions) используется для разрешения конфликтов, если к одному классу применяются несколько расширений с одинаковыми именами методов. - Расширения должны быть явно импортированы в файл, где вы хотите их использовать (
import 'extensions/string_extensions.dart';).