dart語言的庫及其相關語法是瞭解dart應用代碼組織的基礎。網上查找的相關資料每每只是涉及某幾個點,很難有系統性的認識,這裏筆者將結合一些文檔和我的實踐經驗來對dart的庫及其相關語法進行一個梳理。html
dart中,任意一個文件都會被認爲是一個庫,儘管其中可能並無library
標籤,dart庫目前的引入方式大體有三種:git
import 'dart:math';
複製代碼
引入內置庫時,在使用的uri中以dart:
開頭github
import 'package:flutter/material.dart';
複製代碼
在引用包管理器提供的庫時,uri中以package
開頭c#
import './tools/network.dart';
複製代碼
引用本地文件時,uri字符串中直接填寫文件的相對路徑。api
兩個庫中若是存在相同的標識符,在使用時頗有可能會產生衝突;或者在引入一個庫的內容的時候,因爲當前文件引入的庫比較多,致使使用IDE工具提供的標識符名稱聯想時,頗有可能出現一些本不是咱們想要選取,可是首字母相近的內容,影響編碼效率,爲此咱們可使用給庫指定別名的方法,來規避以上問題。bash
import 'package:socket_io_client/socket_io_client.dart' as IO;
class MySocketIO {
IO.Socket mySocket;
MySocketIO(this.mySocket);
}
複製代碼
若是隻想引入庫的部份內容,可使用以下語法:服務器
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
複製代碼
若是想屏蔽庫中的某些內容,不引入這部分:網絡
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
複製代碼
在具體業務中有如下痛點:咱們在應用中定義了多個類或者其餘方法,在引用時咱們想只import一個文件就將相關內容所有導出,若是將全部的類或者方法都放在一個文件中,會致使這個文件十分龐雜,不利於後續維護。爲了解決這個問題,咱們可使用part
、library
和part of
來組織咱們的代碼。
假設咱們的存放公共類和方法的文件爲爲global.dart,其內容可按以下方法組織:app
// 定義庫的名字
library global;
// 文件中引用的公共包
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:i_chat/tools/utils.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './tools/network.dart';
import 'package:dio/dio.dart';
import 'dart:math';
import 'package:provider/provider.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
// 組成這個庫的其餘文件
part './model/User.dart';
part './model/FriendInfo.dart';
part './model/Message.dart';
// ...其餘業務代碼
複製代碼
在文件的開頭使用library
標識符定義庫的名字,這也是其餘子文件與其耦合起來的關鍵,part
標識符指明組成這個庫的其餘文件。須要注意的是,part
部分必定要在import部分的後面。
子文件的組織方式以下,以./model/FriendInfo.dart
爲例:異步
// 指明與其關聯的父庫
part of global;
// 定義其餘內容
class FriendInfo {
...
}
複製代碼
在子文件的開頭,使用part of
標識符,後跟父庫的名字,來指明從屬關係,注意子文件中不須要引入父庫中已經引入的依賴。
在寫其餘業務邏輯代碼的時候只須要直接引入global.dart
文件便可:
import './global.dart';
複製代碼
延遲加載一個庫時,要使用deferred as
來進行導入:
import 'package:greetings/hello.dart' deferred as hello;
複製代碼
在使用時,須要通用調用loadLibrary()
來加載對應的內容
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
複製代碼
儘管你可能在項目中屢次調用loadLibrary()
來加載一個庫,可是這個庫也只會被加載一次。
庫是代碼複用和邏輯模塊化的絕佳手段。庫是以包的形式被創造和分發的。dart語言有兩種類型的包:包含本地庫的應用包(application packages)和庫包(library packages).
下圖展現了一個最簡單的庫包組成結構:
pubspec.yaml
文件在庫包和應用包中是相似的,兩者並無區別。當你建立稱爲迷你庫的小型獨立庫時,庫包最容易維護、擴展和測試。在絕大多數狀況下,每個類應該都以一個迷你庫的形式存在,除非兩個類之間深度耦合。
爲了引出一個庫中的公共api,建議在lib目錄下建立一個'main'文件,方便使用者僅僅經過應用單文件來獲取庫中的全部功能。lib目錄下也有可能包含其餘可引入的庫。例如,若是你的庫能夠跨平臺工做,可是你建立了兩個不一樣的子文件分別依賴dart:io和datr:html。部分包引用了不一樣的庫,在引用這部份內容時須要給他們添加前綴。 接下來咱們觀察一個真實的庫包:shelf,這個包提供了使用Dart語法建立庫的服務器的方法,下圖是其的結構:
export 'src/cascade.dart';
export 'src/handler.dart';
export 'src/handlers/logger.dart';
export 'src/hijack_exception.dart';
export 'src/middleware.dart';
export 'src/pipeline.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/server.dart';
export 'src/server_handler.dart';
複製代碼
shelf包還包括一個迷你庫,shelf_io,他對dart:io中的http請求體進行了簡單的封裝。
當你引用一個庫文件的時候,你可使用package:
指令來指定該文件的URI。
import 'package:utilities/utilities.dart';
複製代碼
對於引用的文件和被引,文件當兩個文件都在lib內部時,或者當兩個文件都在lib外部時,可使用相對路徑導入庫。當其中一個文件在lib目錄內或者外部時,你必須使用package:
。當你猶豫不定的時候,能夠直接會用package:
,這種語法在兩種狀況下均可用。 下面的圖展現瞭如何分別從lib目錄和網絡引入lib/foo/a.dart
:
一個設計良好的庫要便於測試。咱們推薦你使用test包來編寫測試用例,你能夠把測試代碼放在包的頂級目錄中的test
文件夾下。
若是你給用戶建立了命令行工具,請將它們放在bin
文件夾下,以便用戶能夠直接經過pub global activate命令來使用命令行工具。將命令行工具寫在executables section以便用戶能夠直接調用命令行代碼而無需調用pub global run方法.
任何庫本身私有的工具函數或代碼(你不想暴露給使用者),你能夠將它們放在tool
文件夾下。 關於其餘你想要的推送到Pub站點的文件,例如README和CHANGELOG等等,你能夠在Publishing a Pageage中查閱具體內容。
你可使用dartdoc工具來給你的庫添加API註釋。Dartdoc將會解析你的源碼,找到其中經過註釋語法標記的內容,標記示例以下:
/// The event handler responsible for updating the badge in the UI.
void updateBadge() {
...
}
複製代碼
若是你想要開源一個庫,建議你將其分享在Pub site.可使用pub publish
命令來上傳或者更新一個庫。pub site不只僅存儲你的庫,它同時也會自動生成而且保存的你庫的api引用文檔。
爲了確保你的包的API文檔生成正確,你能夠遵循如下步驟: