Библиотеки Libraries

Каждый файл Dart сам по себе является библиотекой, даже без директивы library;

Правило конфиденциальности: Идентификаторы, начинающиеся с нижнего подчеркивания _, являются приватными для библиотеки, видны только внутри этой библиотеки, недоступны между разными файлами/библиотеками;

Ключевых слов public/protected/private не существует; права доступа различаются исключительно по наличию нижнего подчеркивания;

Библиотеки можно упаковать в формат package и управлять через утилиту pub;

Преимущество: Поддержка Tree Shaking (обрезки дерева кода) для удаления неиспользуемого мертвого кода.

import

Используйте ключевое слово import для подключения других библиотек.

import служит для импорта API из сторонних библиотек

Существует три типа URI:

  1. dart:xxx: Встроенные стандартные библиотеки Dart (dart:core, dart:async, dart:js_interop)
  2. package:xxx: Сторонние библиотеки, управляемые pub
  3. Относительные пути к файлам: Локальные пользовательские файлы .dart
// Встроенные стандартные библиотеки
import 'dart:js_interop';
import 'dart:math';

// Сторонние пакеты
import 'package:test/test.dart';

// Локальная файловая библиотека
import './utils.dart';Code language: JavaScript (javascript)

Псевдоним библиотеки as

Если две библиотеки содержат классы/функции с одинаковыми именами, используйте конструкцию as псевдоним для разделения пространств имен и предотвращения конфликтов.

Пример

В файле lib1.dart

class Element {}Code language: JavaScript (javascript)

В lib2.dart есть одноименный класс

class Element {}Code language: JavaScript (javascript)

Основной файл main.dart

// Прямой импорт, стандартное пространство имен
import 'lib1.dart';
// Указать псевдоним lib2
import 'lib2.dart' as lib2;

void main() {
  Element e1 = Element(); // Element из lib1
  lib2.Element e2 = lib2.Element(); // Element из lib2
}Code language: JavaScript (javascript)

Чтобы избежать путаницы, мы задаем для lib2.dart псевдоним lib2, при обращении к его классам достаточно добавить префикс с этим псевдонимом.

Выборочный импорт show / hide

show: Импортировать только указанные имена, все остальное скрыть

// Импортируется только foo, остальные переменные/классы недоступны
import 'lib1.dart' show foo;

void main() {
  foo();
  // bar(); // Ошибка, не импортировано через show, доступ запрещен
}Code language: JavaScript (javascript)

hide: Импортировать все, кроме указанных имен

// Импортировать все, заблокировать только foo
import 'lib2.dart' hide foo;

void main() {
  bar();
  // foo(); // Ошибка, скрыто через hide
}Code language: JavaScript (javascript)

Отложенная загрузка deferred as

Действует только на платформе Web

  • Уменьшить первоначальный объем загрузки веб-страницы;
  • Использовать для редко открываемых модальных окон, дополнительных страниц;
  • Динамически скачивать фрагменты кода по требованию.
  1. Синтаксис импорта: import путь deferred as пространствоИмен
  2. Вызов пространствоИмен.loadLibrary() возвращает Future, используйте await для ожидания завершения загрузки
  3. Многократный вызов loadLibrary() для одной библиотеки произведет загрузку только один раз
  4. Ограничение: константы и типы внутри отложенной библиотеки нельзя использовать напрямую до завершения загрузки

Полный пример

hello.dart (отложенная библиотека)

void printGreeting() {
  print("Hello from deferred library wellcome to foxdevelop.com");
}
Code language: JavaScript (javascript)

main.dart

// Отложенный импорт, псевдоним hello
import 'hello.dart' deferred as hello;

Future<void> greet() async {
  // Динамическая загрузка библиотеки
  await hello.loadLibrary();
  // Только после завершения загрузки можно вызывать внутренние методы
  hello.printGreeting();
}

void main() async {
  await greet();
}
Code language: JavaScript (javascript)

Результат выполнения:

Hello from deferred library wellcome to foxdevelop.com
Code language: JavaScript (javascript)

Оба файла положите в одну папку

Что если hello.dart находится в другой директории, например в родительской папке lib?

Пример пути: D:\dartdemo\firstdart\lib

Файл main.dart лежит по пути D:\dartdemo\firstdart\bin

firstdart/
├─ bin/
│  └─ firstdart.dart       // Точка входа в программу
└─ lib/
   └─ hello.dart      // Библиотека с отложенной загрузкойCode language: JavaScript (javascript)

Тогда импорт записывается так

// ../ обозначает родительскую директорию
import '../lib/hello.dart' deferred as hello;Code language: JavaScript (javascript)

Верхнее объявление библиотеки library

Пишется в самом верху файла, используется для добавления документационных комментариев к библиотеке и аннотаций уровня библиотеки (например, ограничение платформы для тестов).

/// Утилитарная библиотека для тестов только под браузер
@TestOn('browser')
library;
Code language: JavaScript (javascript)

export

Экспорт (инкапсуляция единого публичного API)

Часто используется при разработке пакетов утилит: объединяет несколько подбиблиотек и предоставляет снаружи единственную точку импорта.

Структура файлов проекта

src/math.dart

int add(int a, int b) => a + b;
int sub(int a, int b) => a - b;
Code language: PHP (php)

src/string.dart

String upper(String s) => s.toUpperCase();
Code language: JavaScript (javascript)

utils.dart (единая точка экспорта)

export 'src/math.dart';
export 'src/string.dart';
// Скрыть внутренние приватные утилиты
export 'src/internal.dart' hide helper;
Code language: JavaScript (javascript)

utils.dart нельзя запускать отдельно: это только агрегирующий файл экспорта, не содержит функции входа main(), команда dart run lib/utils.dart не сработает;

Назначение export

  • Объединять API из нескольких подфайлов src;
  • Пользователю достаточно импортировать только файл utils.dart, чтобы получить доступ ко всем открытым методам;
  • hide xxx скрывает внутренние инструменты, инкапсулирует детали реализации и контролирует набор публичных API.

Использование в main.dart

import 'utils.dart';

void main() {
  print(add(1,2));
  print(upper("dart"));
}
Code language: JavaScript (javascript)

Примечание

export/import выполняют только импорт и экспорт на уровне исходного кода; при распространении исходных файлов .dart посторонние могут увидеть весь исходный код;

Чтобы скрыть исходный код, нужно не публиковать исходники .dart, а распространять только скомпилированные бинарные снимки (Snapshot).

Snapshot — бинарный файл, получаемый компиляцией Dart; полностью восстановить читаемый исходный код из него невозможно, можно только вызывать открытые API.

Эта тема разбирается в других курсах.

part

Разделение одной библиотеки на несколько файлов

Одна библиотека разбивается на несколько файлов, между которыми общие приватные идентификаторы с подчеркиванием. Обязательно использовать пару конструкций part 'xxx.dart' / part of 'основной_файл.dart'

main_lib.dart (основной файл библиотеки)

library; // Объявить, что этот файл является библиотекой
part 'logic.dart'; // Объединить logic.dart с текущим файлом, они относятся к одной библиотеке

int _secret = 999; // Приватная переменная библиотеки
Code language: JavaScript (javascript)

logic.dart (фрагментный файл)

part of 'main_lib.dart'; // Объявить, что этот файл принадлежит main_lib.dart, не является самостоятельной библиотекой.

void printSecret() {
  // Можно получить доступ к _secret из основного файла, приватные переменные внутри одной библиотеки видны друг другу
  print(_secret);
}
Code language: JavaScript (javascript)

Вызов кода

import 'main_lib.dart'; // Импортировать основную библиотеку, не импортировать фрагментные файлы

void main() {
  printSecret(); // Выведет 999
}
Code language: JavaScript (javascript)

Условный импорт

Автоматическая смена файлов реализации в зависимости от платформы запуска

import 'platform_stub.dart'
    if (dart.library.io) 'platform_mobile.dart'
    if (dart.library.js_interop) 'platform_web.dart';
Code language: JavaScript (javascript)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *