← Назад к вопросам

Что такое Map?

1.0 Junior🔥 231 комментариев
#Dart

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Map в Dart: Полный гайд

Определение

Map — это коллекция данных, которая хранит пары ключ-значение (key-value pairs). Map — это один из основных data structure'ов в Dart, наряду со List и Set.

// Простой пример
Map<String, int> ages = {
  'John': 25,
  'Jane': 28,
  'Bob': 35,
};

print(ages['John']); // 25
print(ages['Jane']); // 28

Создание Map

1. Литерал синтаксис (рекомендуется)

// С типизацией
Map<String, String> user = {
  'name': 'Alice',
  'email': 'alice@example.com',
  'city': 'New York',
};

// Без типизации (не рекомендуется)
var user = {
  'name': 'Alice',
  'email': 'alice@example.com',
};

// С неоднородными типами (Map<dynamic, dynamic>)
Map<dynamic, dynamic> mixed = {
  'name': 'Alice',
  'age': 30,
  'verified': true,
};

2. Конструктор

// Пустой Map
Map<String, int> empty = Map();
Map<String, int> empty2 = {};

// Map с начальными данными
var numbers = Map<String, int>.from({'a': 1, 'b': 2});

// Из другого Map
var copy = Map.from(original);

// fromEntries (новый синтаксис)
var map = Map.fromEntries([
  MapEntry('a', 1),
  MapEntry('b', 2),
]);

3. Динамическое построение

var config = <String, dynamic>{};
config['host'] = 'localhost';
config['port'] = 8080;
config['debug'] = true;

print(config); // {host: localhost, port: 8080, debug: true}

Основные операции

Доступ к элементам

var user = {
  'name': 'John',
  'age': 30,
};

// Получить значение
print(user['name']); // John

// С безопасностью (может быть null)
print(user['email']); // null (нет ошибки!)

// С default value
print(user['email'] ?? 'no-email'); // no-email

// Проверить наличие ключа
if (user.containsKey('name')) {
  print('Name exists');
}

// Получить все ключи
print(user.keys); // (name, age)

// Получить все значения
print(user.values); // (John, 30)

Изменение элементов

var user = {'name': 'John'};

// Добавить или обновить
user['age'] = 30;
user['name'] = 'Jane'; // Обновить

print(user); // {name: Jane, age: 30}

// putIfAbsent (добавить если ключ не существует)
user.putIfAbsent('city', () => 'New York');
user.putIfAbsent('name', () => 'Alice'); // Не заменит

print(user); // {name: Jane, age: 30, city: New York}

Удаление элементов

var user = {'name': 'John', 'age': 30, 'city': 'NY'};

// Удалить один элемент
user.remove('age');
print(user); // {name: John, city: NY}

// Удалить по условию
user.removeWhere((key, value) => value == 'NY');
print(user); // {name: John}

// Очистить весь Map
user.clear();
print(user); // {}

Итерация по Map

forEach

var user = {'name': 'John', 'age': 30};

user.forEach((key, value) {
  print('$key: $value');
});
// Output:
// name: John
// age: 30

for-in с entries

var user = {'name': 'John', 'age': 30};

for (var entry in user.entries) {
  print('${entry.key}: ${entry.value}');
}

for-in с keys

for (var key in user.keys) {
  print('$key = ${user[key]}');
}

Методы Map

map() — трансформировать значения

var ages = {'John': 25, 'Jane': 28};

// Преобразовать значения
var doubled = ages.map((key, value) => MapEntry(key, value * 2));
print(doubled); // {John: 50, Jane: 56}

// Только значения
var newAges = ages.values.map((age) => age + 1).toList();
print(newAges); // [26, 29]

where() — фильтровать

var ages = {'John': 25, 'Jane': 28, 'Bob': 17};

// Взрослые (age >= 18)
var adults = ages.entries
    .where((entry) => entry.value >= 18)
    .toList();

print(adults); // [MapEntry(John, 25), MapEntry(Jane, 28)]

// Конвертировать обратно в Map
var adultMap = Map.fromEntries(adults);
print(adultMap); // {John: 25, Jane: 28}

update() — обновить значение

var user = {'name': 'John', 'age': 30};

// Обновить если ключ существует
user.update('age', (old) => old + 1);
print(user); // {name: John, age: 31}

// updateAll — обновить все значения
var numbers = {'a': 1, 'b': 2, 'c': 3};
numbers.updateAll((key, value) => value * 10);
print(numbers); // {a: 10, b: 20, c: 30}

addAll() — объединить Map

var map1 = {'a': 1, 'b': 2};
var map2 = {'c': 3, 'd': 4};

map1.addAll(map2);
print(map1); // {a: 1, b: 2, c: 3, d: 4}

// Spread operator (для нового Map)
var merged = {...map1, ...map2};
print(merged); // {a: 1, b: 2, c: 3, d: 4}

Практические примеры

1. JSON (наиболее частый случай)

import 'dart:convert';

// JSON string → Map
var jsonString = '{"name":"John","age":30}';
var map = jsonDecode(jsonString); // Map<String, dynamic>

print(map['name']); // John
print(map['age']); // 30

// Map → JSON string
var user = {'name': 'John', 'age': 30};
var json = jsonEncode(user); // '{"name":"John","age":30}'

2. REST API response

Future<Map<String, dynamic>> fetchUser(String id) async {
  final response = await http.get(Uri.parse('https://api.example.com/users/$id'));
  
  if (response.statusCode == 200) {
    return jsonDecode(response.body) as Map<String, dynamic>;
  }
  throw Exception('Failed to load user');
}

// Использование
var user = await fetchUser('1');
print(user['name']);
print(user['email']);

3. Configuration object

class AppConfig {
  final Map<String, dynamic> _config;
  
  AppConfig(this._config);
  
  String? getString(String key, [String? defaultValue]) {
    return _config[key] ?? defaultValue;
  }
  
  int getInt(String key, [int? defaultValue]) {
    return _config[key] ?? defaultValue;
  }
  
  bool getBool(String key, [bool defaultValue = false]) {
    return _config[key] ?? defaultValue;
  }
}

// Использование
var config = AppConfig({
  'apiUrl': 'https://api.example.com',
  'timeout': 30,
  'debug': true,
});

print(config.getString('apiUrl')); // https://api.example.com
print(config.getInt('timeout')); // 30
print(config.getBool('debug')); // true

4. Кеширование данных

class Cache<K, V> {
  final Map<K, V> _data = {};
  
  V? get(K key) => _data[key];
  
  void set(K key, V value) => _data[key] = value;
  
  bool has(K key) => _data.containsKey(key);
  
  void clear() => _data.clear();
  
  int get size => _data.length;
}

// Использование
final cache = Cache<String, String>();
cache.set('user_1', 'John');
print(cache.get('user_1')); // John
print(cache.has('user_1')); // true

Типичные ошибки

❌ Ошибка 1: Забыть что Map может содержать null

var user = {'name': 'John'};

String name = user['email']!; // ❌ Runtime error!
// Нет ключа 'email', вернется null

✅ Правильно:

String email = user['email'] ?? 'no-email';
String? email = user['email']; // или nullable

❌ Ошибка 2: Изменить Map во время итерации

var map = {'a': 1, 'b': 2, 'c': 3};

for (var key in map.keys.toList()) { // ← toList() ВАЖНО!
  if (key == 'b') {
    map.remove(key);
  }
}

❌ Ошибка 3: Неправильная типизация

Map<String, int> numbers = {'a': 1, 'b': 2};
numbers['c'] = 'three'; // ❌ Type error!

Сравнение Map vs List

ОперацияMapList
Поиск по ключуO(1)O(n)
ДобавлениеO(1)O(1)*
УдалениеO(1)O(n)
ПорядокНет гарантииГарантированный
Наличие дубликатовКлючи уникальныМогут быть
ИспользованиеНастройки, JSONПоследовательности

Итоги

Map в Dart:

  • Коллекция key-value пар для быстрого поиска
  • Основной способ работы с JSON в Dart
  • О(1) поиск по ключу (очень быстро)
  • Динамическая типизация возможна, но типизация предпочтительна
  • Множество методов для трансформации (map, where, update)

Maps — это неотъемлемая часть Dart программирования. От парсинга JSON до конфигурации приложения, Map везде!

Что такое Map? | PrepBro