Flutter插件neodart的介绍与使用方法

Flutter插件neodart的介绍与使用方法

Neo-Dart,或称“新”Dart,是一系列推荐的包和原则,这些原则打破了经典惯例(“我们一直这样做”),并且偏向于变化而不是稳定性。

提示:重要的是,没有人应该被迫使用neo-Dart约定。我们贡献这些是为了帮助其他人理解在构建Dart/Flutter应用程序和库时涉及的一些权衡,但你可以自由地有自己的观点。此外,某些或所有这些指南可能不适用于短暂的原型、周末项目或不需要特别健壮或由他人贡献的东西。

使用

Neo-Dart是一种约定,你只需阅读(并可选地参与)此存储库即可“使用”。

然而,如果你希望使用一组非常有意见性的lint规则来代表这里的约定:

# 添加neodart作为开发依赖。
dart pub add --dev neodart
# analysis_options.yaml
include: package:neodart/neodart.yaml

这些规则包含include: package:lints/core.yaml,然后在此基础上添加额外的更严格的lint规则,始终带有理由/原理。

贡献

要贡献,只需打开一个议题(重大讨论)或发起一个拉取请求(小问题或无需讨论,如拼写修正)。你的请求不一定被接受,但对指南的更改是受欢迎的。

截至2022-07-05,只有matanlurey有权做出决定,希望未来能扩大范围。

要求

  1. 你的请求必须有超出个人偏好的充分文档说明。
  2. 你的请求必须能够用书面英语表达。
  3. 请求形式为“但是X语言/框架/库…”是不够的。

原则

以下是neo-Dart包和代码的原则:

  • 不使用:不应出现在任何非实验性代码中。
  • 避免:应很少出现在非实验性代码中;有良好的文档说明。
  • 考虑:应在适当的时候考虑。
  • 首选:除非有充分文档说明,否则应默认使用。

不使用dart:mirrors

强制执行:无。理想情况下应有一个lint,所以待定。

运行时反射从未在Dart 1.x中完全成熟,并且在现代Dart(2.x)中被降级为第三类公民,不再支持在Dart AOT(即大多数Flutter二进制文件)或任何Dart for Web程序中使用。

此外,即使对于命令行Dart JIT程序,镜像也不再被支持或更新以跟上新的语言范式或原语。

因此,完全不使用dart:mirrors,即使是在测试中。运行时反射通常会使新用户和维护者难以理解包,并变得过于聪明。总会有更好的方法。

不使用或覆盖noSuchMethod

强制执行:无。理想情况下应有一个lint,所以待定。

类似于dart:mirrors,是noSuchMethod,一个用户实现的“catch-all”用于Dart类中未实现的成员。在现代Dart中,它主要用于存根(此类尚未或有意未实现)或模拟(例如,使用类似package:mockito的东西)。

类似于镜像,noSuchMethod在语言中没有跟上,并且具有性能(运行时和代码大小)成本,这些成本对大多数开发人员来说并不明显。

几乎总是有更好的方法来覆盖noSuchMethod。

不进行动态调用

强制执行:通过可选的lint avoid_dynamic_calls

在Dart 1.x中,每个调用都是动态调用,类型签名仅用于(相当有限的)静态分析。从Dart 2.x开始,大多数调用是静态的,动态调用仅限于对象(隐式或显式)类型为dynamic。

动态调用是完全可以避免的技术债务,禁用了任何有用的静态分析,使编译器更难工作(并且在大多数情况下生成更慢和更紧凑的代码),并且越来越容易出错。

可以使用:

  • Object?带类型检查(即is)和类型转换。
  • 类型推断,包括方法泛型。
  • 强类型自定义对象而不是依赖于foo.someMethod()

注意:调用类型为FunctionFunction.apply也是动态调用。

不使用模拟

强制执行:部分通过lint avoid_implementing_value_types,但需要更多;待定。

模拟,或者创建临时代理对象假装实现某种类型,在测试某些对象之间的契约时可能是有用的;例如,你可能希望确保pet.eat(bowl)仅调用一次bowl.grab(...)方法,带有特定参数(宠物的嘴大小?)。

然而,模拟通常被过度使用。典型的应用程序和库通常不需要模拟,最好使用真实对象(特别是对于值类型不可变对象),和/或使用或贡献伪造对象——有意的子类型用于测试。

避免代码生成

强制执行:无;不是硬性规定,易于在代码审查中发现。

作为不使用dart:mirrors的后续,也不要使用代码生成。代码生成是一个强大的工具,但几乎总是被过度使用,并且在Dart生态系统中(截至2022-07-05)支持不足。

为什么避免代码生成:

  • 工具支持不强;build生态系统被认为是“尽力而为”,并未广泛用于Dart团队自身;分析器等工具不理解代码生成的概念。
  • 代码生成往往会产生代码库中不允许的模式,但隐藏在“生成代码”背后。生成的代码并不代表代码质量应该差。
  • 代码生成太慢,不适合大多数严肃的开发周期;通常比运行Dart代码更长,尤其是在虚拟机中。

然而,这条规则是避免,而不是不使用;有针对性地使用代码生成(例如生成API客户端或JSON序列化)是可以的,但应该谨慎使用;尝试在没有代码生成的情况下开发你的功能或库,并缩小模式后再决定是否使用代码生成。

注意:有一些很有前景的语言工作,如,这可能会在未来软化这条规则,但在使用宏时也要小心过度使用。

在开发库时避免重量级依赖

强制执行:无;不是硬性规定,易于在代码审查中发现。

依赖项并不是邪恶的,它们使你能够在不花费时间重新发明轮子的情况下创建任何非琐碎的应用程序(特别是在安全、隐私、性能或低级计算方面)。

然而,当你向包添加非开发依赖项时,要审慎,因为每增加一个依赖项都会使你的库的用户升级和维护越来越困难。你甚至应该考虑使用show当导入其他包中的符号到你的库中:

import 'package:other/other.dart' show ExplicitThingIAmUsing;

例如,当你创建一个假设的number_parser类时,可能会倾向于使用现有的库进行数字格式化、字符串解析或其他任何东西。然而,问问自己是否真正需要许多依赖项中的确切功能,或者是否可以用一个小的(私有的)定制实现。

总结:一般而言,尽量遵循YAGNI政策。

避免创建可以或应该被扩展或实现的类

强制执行:部分通过分析器(@sealedfactory)。

这是效仿《Effective Java》(第17条):

设计和文档说明继承,否则禁止它。

在Dart中,除了文档(即/// Do not extend this class)之外,几乎没有机制可以做到这一点,但以下是一些建议:

  • 使用package:meta中的@sealed;禁止大多数类型的继承:
import 'package:meta/meta.dart';

@sealed
class Animal {
  final String name;

  Animal(this.name);
}
  • 确保你所有的公共构造函数都是工厂构造函数:
class Animal {
  final String name;

  // 工厂构造函数不能被超类调用/使用。
  factory Animal(String name) = Animal._;

  // 私有构造函数防止`extends`和`with`(混合)。
  Animal._(this.name);
}

避免在公共API中使用可变对象

强制执行:无。理想情况下应有一个lint,所以待定。

完全避免可变状态和API并不是理想的选择;归根结底,所有不变性都是抽象的。

然而,在公共API中,除非出于性能或正确性原因需要可变性,否则应设计为不可变避免修改提供给你的对象(除非明确记录你会修改它们):

/// 从[names]中移除与我们的显式名称过滤器匹配的元素。
void removeExplicit(Set<String> names) {
  // OK:在公共API中记录了“names”将被修改。
}

更多关于Flutter插件neodart的介绍与使用方法的实战教程也可以访问 https://www.itying.com/category-92-b0.html

回到顶部