flutter 文件与库的引用导出(import、import as、import show、part、part of、library)

前言

dart语言的库及其相关语法是了解dart应用代码组织的基础。网上查找的相关资料往往只是涉及某几个点,很难有系统性的认识,这里笔者将结合一些文档和个人实践经验来对dart的库及其相关语法进行一个梳理。

库的引入

dart中,任意一个文件都会被认为是一个库,尽管其中可能并没有library标签,dart库目前的引入方式大致有三种:

  • 引入dart语言的内置库:
import 'dart:math';

引入内置库时,在使用的uri中以dart:开头

  • 引入pub包管理器提供库:
import 'package:flutter/material.dart';

在引用包管理器提供的库时,uri中以package开头

  • 引入本地文件:
import './tools/network.dart';

引用本地文件时,uri字符串中直接填写文件的相对路径。

指定库的别名

两个库中如果存在相同的标识符,在使用时很有可能会产生冲突;或者在引入一个库的内容的时候,由于当前文件引入的库比较多,导致使用IDE工具提供的标识符名称联想时,很有可能出现一些本不是我们想要选取,但是首字母相近的内容,影响编码效率,为此我们可以使用给库指定别名的方法,来规避以上问题。

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;

关于part、library和part of

在具体业务中有以下痛点:我们在应用中定义了多个类或者其他方法,在引用时我们想只import一个文件就将相关内容全部导出,如果将所有的类或者方法都放在一个文件中,会导致这个文件十分庞杂,不利于后续维护。为了解决这个问题,我们可以使用partlibrarypart of来组织我们的代码。
假设我们的存放公共类和方法的文件为为global.dart,其内容可按如下方法组织:

//  定义库的名字
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).

  • 应用包通常会依赖其他的包,但是绝不会有自引用,应用包的反面就是库包
  • 库包是其他包的依赖对象,他们自己也会依赖其他包,亦有可能会自引用,它们中往往含有会直接运行的脚本,库包的反面就是应用包

编写一个库包

下图展示了一个最简单的库包组成结构:

image.png

一个库所需的最简内容包括:

  1. pubspec 文件
    pubspec.yaml文件在库包和应用包中是类似的,二者并没有区别。
  2. lib 目录
    正如你直觉感觉的那样,库的代码都在lib目录下,这部分内容对其他包也是可见的。如果需要的话,你可以在lib文件夹下创造其他层级的文件,按照惯例,逻辑实现的代码通常放在lib/src目录下。在该目录下的文件通常被认为是私有的。其他的包不应引入src目录下的内容从而暴露lib/scr中的API,正确的使用方法是从lib目录下的其他文件中引出内容。

组织一个库包

当你创建称为迷你库的小型独立库时,库包最容易维护、扩展和测试。在绝大多数情况下,每一个类应该都以一个迷你库的形式存在,除非两个类之间深度耦合。
为了引出一个库中的公共api,建议在lib目录下创建一个'main'文件,方便使用者仅仅通过应用单文件来获取库中的所有功能。lib目录下也有可能包含其他可引入的库。例如,如果你的库可以跨平台工作,但是你创建了两个不同的子文件分别依赖dart:io和datr:html。部分包引用了不同的库,在引用这部分内容时需要给他们添加前缀。 接下来我们观察一个真实的库包:shelf,这个包提供了使用Dart语法创建库的服务器的方法,下图是其的结构:

image.png

在lib目录下的主文件shelf.dart暴露了lib/src下的其他文件中的内容给使用者:

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

image.png

提供其他文件(测试代码、命令行工具)

一个设计良好的库要便于测试。我们推荐你使用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文档生成正确,你可以遵循以下步骤:

  • 在你推送你的包之前,运行dartdoc工具确保你的文档生成正确并且展示符合预期
  • 在你推送你的包之后,检查Vesion tab去报你的文档生成正确
  • 如果文档生成失败,检查dartdoc的输出

总结

  • import 'dart:xxx'; 引入Dart标准库
  • import 'xxx/xxx.dart';引入绝对路径的Dart文件
  • import 'package:xxx/xxx.dart'; 引入Pub仓库pub.dev(或者pub.flutter-io.cn)中的第三方库
  • import 'package:project/xxx/xxx.dart';引入自定义的dart文件
  • import 'xxx' show compute1,compute2 只导入compute1,compute2
  • import 'xxx' hide compute3 除了compute都引入
  • import 'xxx' as compute4 将库重命名,当有名字冲突时
  • library compute5; 定义库名称
  • part of compute6; 表示文件属于某个库

文件导入顺序(从上到下依次)

dart sdk 内的库
flutter内的库
第三方库
自己的库(文件)
相对路径引用
e.g.
import 'dart:io';
import 'package:material/material.dart';
import 'package:dio/dio.dart';
import 'package:project/common/uitls.dart';
import 'xxx/xxx/xxx/xxx.dart';

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容