Menu
Coddy logo textTech

Поля 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.

challenge icon

Задание

Легко

Давайте создадим систему каталога товаров, которая демонстрирует разницу между полями 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)
  
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование