Dart: вопросы на собеседовании (ООП и язык)
Class, abstract class, implements, extends: что выбирать?
class: обычный классabstract class: нельзя создать напрямую, можно описать контракт и/или базовую реализациюextends: наследование реализацииimplements: реализуете интерфейс, обязаны переопределить всё
dart
abstract class Storage {
Future<void> save(String key, String value);
Future<String?> read(String key);
}
class MemoryStorage implements Storage {
final _data = <String, String>{};
@override
Future<void> save(String key, String value) async {
_data[key] = value;
}
@override
Future<String?> read(String key) async {
return _data[key];
}
}Mixin: зачем нужен?
Mixin добавляет поведение без наследования и без необходимости создавать отдельный объект-композицию.
dart
mixin Logger {
void log(String message) {
print(message);
}
}
class Service with Logger {
void run() {
log('running');
}
}Конструкторы: обычный, именованный, factory, const
dart
class User {
final String id;
final String name;
const User(this.id, this.name);
const User.guest()
: id = 'guest',
name = 'Guest';
factory User.fromMap(Map<String, Object?> map) {
final id = map['id'] as String;
final name = map['name'] as String;
return User(id, name);
}
}constконструктор позволяет создавать compile-time константы, если поля тожеfinalи значения константныеfactoryможет вернуть кешированный объект или объект другого класса
Иммутабельность и copyWith
Типичный паттерн для состояния.
dart
class Profile {
final String name;
final int age;
const Profile({required this.name, required this.age});
Profile copyWith({String? name, int? age}) {
return Profile(
name: name ?? this.name,
age: age ?? this.age,
);
}
}Generics: что часто спрашивают?
- зачем нужны (типобезопасность без кастов)
- как ограничивать типы
dart
T firstOrDefault<T>(List<T> items, T fallback) {
return items.isEmpty ? fallback : items.first;
}
class Box<T> {
final T value;
const Box(this.value);
}typedef и alias функций
dart
typedef IntMapper = int Function(int);
int apply(int x, IntMapper mapper) => mapper(x);sealed / base / interface (Dart 3): что это?
Если спросят, обычно ожидают идею:
sealed: все подтипы должны быть объявлены в том же файле, удобно для исчерпывающих проверокbase: ограничивает наследование/реализацию за пределами пакетаinterface: запрещает наследование реализации, только контракт (внешне похоже наimplements)
Pattern matching (Dart 3): базовая идея
dart
String classify(Object value) {
return switch (value) {
int _ => 'int',
String _ => 'string',
_ => 'other',
};
}Исключения: когда throw, когда Error?
Exceptionобычно для ожидаемых ошибок домена/ввода/сетиErrorчаще про программные ошибки (неправильные инварианты), в приложениях их обычно не используют как часть логики
dart
Never fail(String message) {
throw Exception(message);
}