Поля Final и Const
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 18 из 110.
При объявлении полей в классе вы можете использовать final или const, чтобы контролировать, могут ли значения изменяться после инициализации. Оба создают неизменяемые значения, но работают по-разному.
Поле final может быть установлено только один раз, но его значение определяется во время выполнения. Вы можете присвоить его при объявлении или через конструктор:
class Person {
final String name;
final DateTime createdAt = DateTime.now();
Person(this.name);
}
Person p = Person('Alice');
// p.name = 'Bob'; // Ошибка: нельзя переназначить final полеСвойство name устанавливается при создании объекта, а createdAt фиксирует текущее время. Оба значения блокируются после инициализации.
Поле static const должно иметь значение, известное во время компиляции. Оно принадлежит самому классу и является общим для всех экземпляров:
class Circle {
static const double pi = 3.14159;
final double radius;
Circle(this.radius);
double get area => Circle.pi * radius * radius;
}Ключевое отличие: поля final могут содержать значения, вычисляемые во время выполнения (например, DateTime.now()), в то время как const требует констант времени компиляции. Поля экземпляра не могут быть const напрямую — на уровне класса разрешено только static const.
Задание
ЛегкоДавайте создадим систему каталога товаров, которая демонстрирует разницу между полями final и static const. Вы создадите товары с неизменяемыми свойствами и общими значениями конфигурации.
Вы организуете свой код в два файла:
product.dart: Определите классProduct, который представляет товар в магазине. Ваш класс должен иметь:static const double taxRate, установленную в0.08(налоговая ставка 8%, общая для всех товаров)static const String currency, установленную в'USD'final String nameдля названия товара (устанавливается через конструктор)final double basePriceдля базовой цены товара (устанавливается через конструктор)final String sku(артикул), который объединяет префикс с названием товара, вычисляемый в списке инициализации как'SKU-', за которым следует название в верхнем регистре- Конструктор, который принимает
nameиbasePrice - Геттер
priceWithTax, который рассчитывает цену с учетом налога - Метод
display(), который выводит информацию о товаре
main.dart: Импортируйте ваш класс продукта и создайте два товара:'Laptop'с базовой ценой999.99'Mouse'с базовой ценой29.99
display()для каждого товара в указанном выше порядке.
Метод display() должен выводить данные в следующем формате:
[sku] - [name]: [basePrice] [currency] (with tax: [priceWithTax] [currency])Округлите priceWithTax до 2 знаков после запятой, используя toStringAsFixed(2) при выводе.
Ожидаемый вывод:
SKU-LAPTOP - Laptop: 999.99 USD (with tax: 1079.99 USD)
SKU-MOUSE - Mouse: 29.99 USD (with tax: 32.39 USD)Шпаргалка
Используйте final для полей, которые устанавливаются один раз во время выполнения и не могут быть изменены впоследствии. Используйте static const для констант времени компиляции, общих для всех экземпляров класса.
Поля final устанавливаются во время выполнения и могут быть инициализированы при объявлении или в конструкторе:
class Person {
final String name;
final DateTime createdAt = DateTime.now();
Person(this.name);
}Поля static const должны иметь значения, являющиеся константами времени компиляции, и принадлежать самому классу:
class Circle {
static const double pi = 3.14159;
final double radius;
Circle(this.radius);
double get area => Circle.pi * radius * radius;
}Вы можете вычислять значения полей final в списке инициализации:
class Product {
final String name;
final String sku;
Product(this.name) : sku = 'SKU-${name.toUpperCase()}';
}Ключевые различия:
final: значения времени выполнения, могут быть разными для каждого экземпляраstatic const: константы времени компиляции, общие для всех экземпляров- Поля экземпляра не могут быть
constнапрямую — разрешено толькоstatic const
Попробуйте сами
import 'product.dart';
void main() {
// TODO: Создайте Product с названием 'Laptop' и базовой ценой 999.99
// TODO: Создайте Product с названием 'Mouse' и базовой ценой 29.99
// TODO: Вызовите display() для каждого продукта по порядку (сначала Laptop, затем Mouse)
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий