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文档生成正确,你能够遵循如下步骤: