Что такое ключевое слово external в Dart и где оно применяется?

«Что такое ключевое слово external в Dart и где оно применяется?» — вопрос из категории Dart Core, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ключевое слово external в Dart используется для объявления функции или метода, реализация которого предоставляется вне Dart-кода — обычно в нативной платформе (через dart:ffi) или в платформо-специфичных имплементациях Dart SDK.

Основные сценарии использования в моей практике с Flutter:

  1. Интеграция с нативным кодом через dart:ffi
    
    import 'dart:ffi';
    import 'package:ffi/ffi.dart';

// Объявление external функции из нативной библиотеки final DynamicLibrary nativeLib = DynamicLibrary.open('libnative_audio.dylib');

// External функция, реализованная в C/C++ external int processAudioFrame( Pointer inputBuffer, Pointer outputBuffer, int frameSize, );

// Использование в Dart-коде void processAudio(List input) { final inputPtr = calloc(input.length); final outputPtr = calloc(input.length);

for (var i = 0; i < input.length; i++) { inputPtr[i] = Float(input[i]); }

final result = processAudioFrame(inputPtr, outputPtr, input.length);

// Обработка результата... calloc.free(inputPtr); calloc.free(outputPtr); }


2. **Платформо-специфичные реализации в Dart SDK**
При изучении исходного кода Dart SDK можно встретить такие конструкции:
```dart
// В dart:io
abstract class File {
  external factory File(String path);

  external Future<RandomAccessFile> open({FileMode mode = FileMode.read});

  // Реализация предоставляется отдельно для каждой платформы
  // через аннотацию @patch в patch-файлах
}
  1. Генерация кода через аннотации

    // В библиотеках для кодогенерации
    @JsonSerializable()
    class User {
    final String name;
    final int age;
    
    User(this.name, this.age);
    
    // External factory, реализация генерируется build_runner
    external factory User.fromJson(Map<String, dynamic> json);
    
    external Map<String, dynamic> toJson();
    }

Ограничения и особенности:

  • external члены не могут быть async, sync*, или async*
  • Реализация должна быть предоставлена во время выполнения
  • Часто используется с аннотацией @patch в исходном коде Dart SDK
  • Требует точного соответствия сигнатур между объявлением и реализацией

Практический пример из Flutter-разработки: При создании плагина для Flutter, который использует нативные API iOS/Android, external методы позволяют объявить интерфейс в Dart, в то время как реализация предоставляется в Objective-C/Swift или Java/Kotlin через механизм платформенных каналов (Platform Channels) или dart:ffi.