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

Какие типы данных можно передавать в изолят?

2.0 Middle🔥 161 комментариев
#State Management#Архитектура Flutter

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

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

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

Типы данных, которые можно передавать в изолят

Изолят в Dart — это независимый поток выполнения, который работает в отдельной памяти. Это требует особого внимания к тому, какие данные можно туда передавать, так как изоляты не могут напрямую делиться ссылками на объекты.

Типы данных для передачи в изолят

1. Примитивные типы

Все базовые типы данных передаются без проблем:

int number = 42;
double fraction = 3.14;
bool flag = true;
String text = "Hello";
Null nullValue = null;

// Отправить в изолят
isolate.send(number);
isolate.send(text);

Эти типы простые и не требуют копирования сложных структур.

2. Коллекции (List, Map, Set)

Коллекции передаются, но с ограничениями. Элементы коллекции должны быть sendable (передаваемыми):

List<int> numbers = [1, 2, 3];
Map<String, int> data = {'a': 1, 'b': 2};
Set<String> tags = {'flutter', 'dart'};

isolate.send(numbers);  // OK
isolate.send(data);     // OK если ключи и значения sendable

3. Простые классы (Plain Old Dart Objects)

Простые классы с примитивными полями работают, но нужно учитывать ограничения:

class User {
  final String name;
  final int age;
  
  User(this.name, this.age);
}

// Можно отправить
isolate.send(User('John', 30));

Важно: Если класс имеет сложные поля (другие объекты, функции) — это не сработает.

4. Числовые типы всех размеров

Int, double, BigInt — все передаются нормально.

bigInt num = BigInt.from(123456789123456789);
isolate.send(num);

Типы данных, которые НЕЛЬЗЯ передавать

1. Функции и замыкания

Нельзя отправить функцию или замыкание в изолят — нарушается правило изоляции:

// Ошибка!
Function myFunction = (x) => x * 2;
isolate.send(myFunction); // Не сработает!

2. Объекты с методами

Объекты классов, которые имеют методы (кроме примитивных getter'ов) — не передаются:

class Database {
  void query() { ... }
}

// Ошибка!
isolate.send(Database()); // Не сработает!

3. Future, Stream, и другие async типы

Нельзя отправить Future или Stream в изолят напрямую:

Future<int> future = Future.value(42);
isolate.send(future); // Ошибка!

4. Объекты с native-кодом

Объекты, завёрнутые в нативный код (например, File, Socket), не передаются:

File file = File('/path/to/file');
isolate.send(file); // Ошибка!

5. Объекты с приватными полями (в некоторых случаях)

Это может быть сложным в зависимости от сложности структуры.

6. Рекурсивные структуры данных

Данные, которые ссылаются сами на себя, могут вызвать проблемы.

Способы передачи сложных данных

Если нужно передать сложные данные, есть несколько подходов:

1. Сериализация в JSON

Преобразовать объект в JSON и отправить строку:

class User {
  final String name;
  final int age;
  
  Map<String, dynamic> toJson() => {
    'name': name,
    'age': age,
  };
  
  factory User.fromJson(Map<String, dynamic> json) {
    return User(json['name'], json['age']);
  }
}

// Отправить в изолят
String jsonString = jsonEncode(user.toJson());
isolate.send(jsonString);

// В изоляте
User user = User.fromJson(jsonDecode(receivedJson));

2. Использование json_serializable

Для больших приложений лучше использовать генерацию кода:

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final String name;
  final int age;
  
  User(this.name, this.age);
  
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

3. Использование message passing с SendPort

Для более сложных сценариев используй SendPort для двусторонней коммуникации:

SendPort sendPort = await Isolate.spawn(
  isolateEntryPoint,
  receivePort.sendPort,
);

// Отправить команду в изолят
sendPort.send({
  'command': 'process',
  'data': 'some data',
});

4. Передача путей вместо объектов

Для файлов и БД передавай пути/ID вместо самих объектов:

// Вместо отправки File
isolate.send('/path/to/file');

// В изоляте открыть файл по пути
File file = File(receivedPath);

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

void main() async {
  final receivePort = ReceivePort();
  
  await Isolate.spawn(
    computeHeavyTask,
    receivePort.sendPort,
  );
  
  final sendPort = await receivePort.first as SendPort;
  
  // Отправить данные
  sendPort.send({
    'numbers': [1, 2, 3, 4, 5],
    'multiplier': 2,
  });
  
  // Получить результат
  receivePort.listen((message) {
    print('Result: $message');
  });
}

void computeHeavyTask(SendPort sendPort) {
  final receivePort = ReceivePort();
  sendPort.send(receivePort.sendPort);
  
  receivePort.listen((message) {
    final numbers = message['numbers'] as List<int>;
    final multiplier = message['multiplier'] as int;
    
    final result = numbers.map((n) => n * multiplier).toList();
    sendPort.send(result);
  });
}

Итог

Можно передавать:

  • Примитивные типы (int, double, String, bool, null)
  • Простые коллекции (List, Map, Set) с sendable элементами
  • Простые классы только с примитивными полями

Нельзя передавать:

  • Функции и замыкания
  • Объекты с методами
  • Future, Stream
  • Native объекты (File, Socket)

Решение для сложных данных:

  • JSON сериализация
  • SendPort для двусторонней коммуникации
  • Передача путей/ID вместо объектов

Это требует продуманной архитектуры при работе с изолятами.