Libraries 函式庫

每個 Dart 檔案天生就是一個函式庫,就算不寫 library 指令;

隱私權限規則:識別字底線 _ 開頭 = 函式庫私有,僅同函式庫內可見,跨檔案/函式庫無法存取;

Dart 沒有 public/protected/private 關鍵字,僅靠底線區分存取權限;

函式庫可打包為 package 交由 pub 套件管理工具管理;

優勢:有利樹搖最佳化(Tree Shaking),移除未使用的多餘死程式碼。

import 匯入

使用 import 關鍵字匯入其他函式庫。

import 用來載入其他函式庫提供的 API

URI 分為三類:

  1. dart:xxx:Dart 內建標準函式庫(dart:coredart:asyncdart: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(); // lib1 的 Element
  lib2.Element e2 = lib2.Element(); // lib2 的 Element
}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 的用途

  • 聚合多個 src 子檔案的 API;
  • 使用者只需匯入 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)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *