Irbisa · Шпаргалка
Система типов Dart в глубину
Верхние и нижние типы, reified-дженерики, вариантность, вывод типов, FutureOr, extension type
В Dart три top-типа:
Object?,dynamicиvoid. Чем они отличаются и почемуObjectк ним не относится?Что такое тип
Neverи когда функция должна возвращатьNever, а неvoid?// wrong: void; the call is an ordinary statement, flow continues past itvoid failVoid(String m) => throw StateError(m); // right: Never; the call does not returnNever fail(String m) => throw StateError(m);…Что значит, что система типов Dart является sound, и какие проверки типов всё ещё выполняются во время выполнения?
Как flow analysis решает, что продвигают проверка на null и
is, и что отменяет продвижение?void demo(Object value, String? path) { if (value is! String) return; print(value.length); // String for the rest of the body if (path == null) throw ArgumentError.notNull('path'); print(path.length); // String: the null branch cannot continue…Дженерики в Dart реифицированы, в отличие от Java. Что можно делать с аргументом типа во время выполнения и чего по-прежнему нельзя?
import 'dart:convert'; void main() { final tags = jsonDecode('["a", "b"]'); print(tags.runtimeType); // List<dynamic>, fixed when the list was created…В чём разница между
x is Tиx.runtimeType == Tи почемуruntimeTypeне стоит использовать в логике?import 'dart:convert'; class Animal {} class Dog extends Animal { void bark() {}…Как работает вывод типов в Dart и когда он молча откатывается к
dynamic?import 'dart:convert'; class Animal {}class Dog extends Animal {}class Cat extends Animal {}…Этот код присваивает
List<Dog>переменнойList<Animal>и добавляетCat. Скомпилируется ли он и что произойдёт при запуске?class Animal {}class Dog extends Animal {}class Cat extends Animal {} void addStray(List<Animal> animals) => animals.add(Cat()); void main() { final dogs = <Dog>[Dog()]; final List<Animal> animals = dogs; print(animals.length); addStray(animals); print(dogs.length);}Что делает ключевое слово
covariantу параметра и почемуoperator ==должен приниматьObject other?class Animal {} class Dog extends Animal {} abstract class Handler { void handle(covariant Animal a); // overrides may narrow `a`…В этом парсере нигде нет
as, но он падает сtype 'Null' is not a subtype of type 'int'. Откуда взялся каст?class User { final int id; final String name; User(this.id, this.name); factory User.fromJson(Map<String, dynamic> json) { final int id = json['id']; return User(id, json['name']); }} void main() { print(User.fromJson({'name': 'Ada'}).name);}Найдите баг:
get<AuthRepository>()бросает «AuthRepository is not registered» сразу после того, как приложение зарегистрировало репозиторий.abstract interface class AuthRepository {}class HttpAuthRepository implements AuthRepository {} class Locator { final _services = <Type, Object>{}; void register<T extends Object>(T service) => _services[T] = service; T get<T extends Object>() => _services[T] as T? ?? (throw StateError('$T is not registered'));} void main() { final locator = Locator()..register(HttpAuthRepository()); print(locator.get<AuthRepository>());}Почему
void Function(Object)можно передать туда, где ожидаетсяvoid Function(Dog), аvoid Function(Dog)не подходит на местоvoid Function(Animal)?class Animal {} class Dog extends Animal { void fetch() {}}…Ваш
maxOf<T extends Comparable<T>>работает дляDateTimeи собственногоMoney, ноmaxOf<int>не компилируется. Почему и что написать вместо этого?// F-bound: T must be comparable to its own kindT maxOf<T extends Comparable<T>>(List<T> xs) => xs.reduce((a, b) => a.compareTo(b) >= 0 ? a : b); class Money implements Comparable<Money> { final int cents;…Что такое extension type, чем он отличается от класса-обёртки и где его гарантия исчезает во время выполнения?
extension type UserId(String value) { bool get isValid => value.isNotEmpty; // String toString() => ...; // error: conflicts with a member of Object} // `implements` exposes the representation's members…Найдите баг: в логах видны полные номера телефонов, хотя каждое поле лога проходит через
mask.extension type Email(String value) {}extension type Phone(String value) {} // Masks personal data before a log field is written.String mask(Object? field) { if (field is Email) { return '***@${field.value.split('@').last}'; } if (field is Phone) { return '***${field.value.substring(field.value.length - 4)}'; } return '***';} void main() => print(mask(Phone('+77011234567')));Что напечатает этот код и что он говорит о
FutureOr<T>как о типе?import 'dart:async'; FutureOr<Object> load() => Future<String>.value('data'); Future<void> main() async { final raw = load(); print(raw is Future); final v = await raw; print(v.runtimeType); print(<FutureOr<Object?>>[] is List<Object?>);}Код, полный
Map<String, dynamic>, проходит анализ без замечаний и всё равно падает на кастах. Что ловятstrict-casts,strict-raw-typesиstrict-inference?# analysis_options.yamlinclude: package:flutter_lints/flutter.yaml analyzer: language: strict-casts: true # String name = json['name']; -> error…Вы публикуете пакет, главный класс которого является дженериком. Как сделать его публичный API типобезопасным для вызывающих?
// wrong: unbounded; Cache<String, int?> makes `null` mean two thingsclass LooseCache<K, V> { final _m = <K, V>{}; V? get(K key) => _m[key]; // "absent" or "stored null"?}…