Flutter Lint规则详解--代码规范

365 阅读15分钟

Flutter Lint规则详解--代码规范

WechatIMG194.jpg

前言

Flutter中通过analysis_options.yaml设置lint规则,可以自定义规则的等级(error、warning、info、ignore),可以设置不受规则限制的文件。

配置文件分析

设置analysis_options.yaml

  • 启用更严格的类型检查
analyzer:
  language:
    # 类型推理引擎不再将 dynamic 进行隐式类型转换
    strict-casts: true
    # 当类型推理引擎无法确定静态类型时,不再选择dynamic 类型
    strict-inference: true
    # 强制类型安全 由于省略类型参数而无法确定静态类型时,不再选择dynamic 类型
    strict-raw-types: true
  • 启用停用linter规则,修改规则等级,字段值有ignore、error、warning、info
analyzer:
  errors:
    #使用print的lint等级改为error
    avoid_print: warning
    unsafe_html: error
    always_declare_return_types: ignore
    
  • 设置不受规则限制的文件
analyzer:
  exclude:
    - "bin/cache/**"
      # Ignore protoc generated files
    - "dev/conductor/lib/proto/*"

Lint规则解析

建议设置为error的规则

  1. avoid_web_libraries_in_flutter

    不要使用仅在web中支持的库

    dart.dev/tools/linte…

  2. unsafe_html

    不使用不安全的html api

    dart.dev/tools/linte…

  3. depend_on_referenced_packages

    依赖的库应该在dependcies中指定版本号

    dart.dev/tools/linte…

  4. avoid_js_rounded_ints

    不用使用难以转换为js的数字

     // bad
     int value = 9007199254740995;
    
     // good
     BigInt value = BigInt.parse('9007199254740995');
    

    dart.dev/tools/linte…

  5. avoid_print

    不使用print,使用debugPrint

    dart.dev/tools/linte…

  6. always_declare_return_types

    声明方法或函数时,始终要指定返回类型

    dart.dev/tools/linte…

  7. always_specify_types

    显式地声明所有变量、字段、参数和返回值的类型

    当指定未知类型和省略类型时,避免使用var。如果明确表示类型未知,则使用dynamic

    dart.dev/tools/linte…

  8. avoid_dynamic_calls

    避免对 dynamic 类型的对象进行调用,需明确类型

     void main() {   
         // bad
         dynamic person = getPerson();   
         person.sayHello();  
    
         // good
         Person person = getPerson();   
         person.sayHello();  
     }
    

    dart.dev/tools/linte…

  9. test_types_in_equals

    复写类的==方法时,一定要判断入参的类型,以防止传入null等

    dart.dev/tools/linte…

  10. annotate_overrides

    重写父类方法或变量时要用overrides修饰

    abstract class Dog {
      String get breed;
      void bark() {}
    }
    
    class Husky extends Dog {
      @override
      final String breed = 'Husky';
      @override
      void bark() {}
    }
    

    dart.dev/tools/linte…

  11. avoid_shadowing_type_parameters

    类型参数不要重复使用,引起歧义

    class A<T> {  
        // bad
        void fn<T>() {}
        // good
        void fn<U>() {}
    }
    

    dart.dev/tools/linte…

  12. await_only_futures

    避免使用await修饰非Future,null可以作为特殊情况

    main() async {  
        // bad
        print(await 23);
    }
    

    dart.dev/tools/linte…

  13. cancel_subscriptions

    StreamSubscription一定要记得cancel

    dart.dev/tools/linte…

  14. cast_nullable_to_non_nullable

    不要将可空值? as成不可空值

    dart.dev/tools/linte…

  15. collection_methods_unrelated_type

    使用集合的方法不要传入与集合类型不相符的参数

    final List<int> list = <int>[1,2,3];
    // 类型不符
    if (list.contains('a')) {
       print('');
    }
    

    dart.dev/tools/linte…

  16. valid_regexps

    使用有效的正则语法

    dart.dev/tools/linte…

  17. conditional_uri_does_not_exist

    条件导入中,不要使用不存在的路径

    import 'file_that_does_exist.dart'
       // bad
      if (condition) 'file_that_does_not_exist.dart';
    

    dart.dev/tools/linte…

  18. no_duplicate_case_values

    Switch case 中case不要重复

    dart.dev/tools/linte…

  19. no_self_assignments

    不要将变量赋值给自身

    class C {
      int x;
       // bad
      C(int x) {
        x = x;
      }
      // good 
      C(int x) {    
          this.x = x;  
      }
    }
    

    dart.dev/tools/linte…

  20. no_logic_in_create_state

    在createState()中不要写逻辑代码

    dart.dev/tools/linte…

  21. null_check_on_nullable_type_parameter

    不要对可能为空的对象使用 !

    dart.dev/tools/linte…

  22. overridden_fields

    不要覆盖父类的属性

    class Parent {
      String name = 'Parent';
    }
    
    class Child extends Parent {
      // 覆盖了父类中的字段
      int name = 42;  
    }
    
    void main() {
      Child child = Child();
      print(child.name);  // 这里会产生混淆
    }
    

    dart.dev/tools/linte…

  23. prefer_const_constructors

    使用const来修饰具有const构造方法产生的对象

    class A {
      const A();
    }
    
    void accessA() {
      A a = const A();
    }
    

    dart.dev/tools/linte…

  24. prefer_const_constructors_in_immutables

    对于不可变的类,需要使用const来修饰构造方法

    @immutable
    class A {
      final a;
      // const 修饰
      const A(this.a);
    }
    

    dart.dev/tools/linte…

  25. prefer_const_literals_to_create_immutables

    使用const 作为 @immutable 类的初始化参数

    A a1 = A(const [1]);
    A a2 = A(const {});
    

    dart.dev/tools/linte…

  26. null_closures

    避免将 null 作为函数类型参数的默认值

    // bad
    void exampleFunction({void Function()? callback = null}) {
      if (callback != null) {
        callback(); // 可能会导致运行时错误
      }
    }
    // good
    void exampleFunction({void Function()? callback}) {
      callback?.call(); // 安全调用
    }
    

    dart.dev/tools/linte…

  27. prefer_typing_uninitialized_variables

    未在定义的时候初始化的变量应该指明类型

    class BadClass {
    // bad
      var foo; 
      // good
      int number;
    
    }
    

    dart.dev/tools/linte…

  28. avoid_unnecessary_containers

    没有必要的containers 会造成Widget树臃肿

    https://darts/linter-rules/avoid_unnecessary_containers

  29. sized_box_for_whitespace

    布局添加空白使用sizebox代替container,sizeBox更轻量,而且可以用const

    dart.dev/tools/linte…

  30. use_colored_box

    仅设置颜色时使用ColoredBox组件 代替Container

    dart.dev/tools/linte…

  31. hrow_in_finally

    try catch final的 finally中不应该抛出error

    dart.dev/tools/linte…

  32. unnecessary_null_aware_assignments

    避免不必要的空值感知赋值操作符 ??=

    void main() {
      int? a;
      a ??= 5;  // 如果 a 为 null,则赋值为 5
      a ??= 10; // 这行代码是多余的,因为 a 已经不为 null
    }
    

    dart.dev/tools/linte…

  33. unreachable_from_main

    不要再函数入口处定义无法执行到的代码

    main() {
    }
    // f函数无调用,无法执行到
    void f() {
    }
    

    dart.dev/tools/linte…

  34. use_build_context_synchronously

    仅在同步方法中使用BuildContext,异步方法中可能context已销毁

    void onButtonTapped(BuildContext context) async {
      await Future.delayed(const Duration(seconds: 1));
      Navigator.of(context).pop();
    }
    

    dart.dev/tools/linte…

  35. unnecessary_statements

      避免使用无意义的代码,无用的语句应及时删除

    void main() {
      int a = 5;
      a;  // 这是一条不必要的语句,没有任何效果
      print(a);
    }
    

      dart.dev/tools/linte…

  1. avoid_returning_null_for_void

      声明void返回值的函数不要返回null,减少由于误解 null 返回值所导致的潜在错误

    // bad
    Future<void> f2() async {  
        return null;
    }
    //good
    Future<void> f2() async {  
        return;
    }
    

      dart.dev/tools/linte…

  1. hash_and_equals

    重写==运算符时要同步重写hashCode

    dart.dev/tools/linte…

  2. use_key_in_widget_constructors

      自定义的 Widget 构造函数中始终包含一个可选的 Key 参数,以提高性能和可靠性

    class MyPublicWidget extends StatelessWidget {  
        MyPublicWidget({super.key});
    }
    

      dart.dev/tools/linte…

  1. avoid_void_async

    异步方法不要直接返回void 返回Future,确保异步函数返回的是Future

    // bad
    void f() async {}
    // good
    Future<void> f() async {}
    

    dart.dev/tools/linte…

完整analysis_options.yaml文件(附每条规则的中文说明)

摘自github.com/flutter/pac…

# Specify analysis options.
#
# For a list of lints, see: https://dart.dev/lints
# For guidelines on configuring static analysis, see:
# https://dart.dev/guides/language/analysis-options
#
# There are other similar analysis options files in the flutter repos,
# which should be kept in sync with this file:
#
#   - analysis_options.yaml (this file)
#   - https://github.com/flutter/engine/blob/main/analysis_options.yaml
#   - https://github.com/flutter/packages/blob/main/analysis_options.yaml
#
# This file contains the analysis options used for code in the flutter/flutter
# repository.

analyzer:
  language:
    # https://dart.cn/tools/analysis 
    # 类型推理引擎不再将 dynamic 进行隐式类型转换
    strict-casts: true
    # 当类型推理引擎无法确定静态类型时,不再选择dynamic 类型
    strict-inference: true
    # 强制类型安全 由于省略类型参数而无法确定静态类型时,不再选择dynamic 类型
    strict-raw-types: true
  errors:
    # allow self-reference to deprecated members (we do this because otherwise we have
    # to annotate every member in every test, assert, etc, when we deprecate something)
    deprecated_member_use_from_same_package: ignore
    avoid_print: error
    avoid_web_libraries_in_flutter: error
    unsafe_html: error
  exclude:
    - "bin/cache/**"
      # Ignore protoc generated files
    - "dev/conductor/lib/proto/*"

linter:
  rules:
    # This list is derived from the list of all available lints located at
    # https://github.com/dart-lang/linter/blob/main/example/all.yaml

    # 声明方法或函数时,始终要指定返回类型
    - always_declare_return_types 
    # 不要使用仅在web中支持的库
    - avoid_web_libraries_in_flutter
    # 明确指定类型。当指定未知类型和省略类型时,避免使用var。如果明确表示类型未知,则使用dynamic
    - always_specify_types
    # 定义函数参数、泛型时,避免直接使用dynamic的对象,需指定明确类型
    - avoid_dynamic_calls
    # 使用父类参数要用overrides修饰
    - annotate_overrides
    # 不用使用难以转换为js的数字
    - avoid_js_rounded_ints
    # 不使用print
    - avoid_print
    # 在组件的构造方法中一定要使用key,并调用super将key传入super的初始化方法.
    - use_key_in_widget_constructors
    # 声明void返回值的函数不要返回null
    - avoid_returning_null_for_void
    # 类型参数不要重复使用,引起歧义
    - avoid_shadowing_type_parameters
    # 不要使用没有必要的containers 会造成Widget树臃肿
    - avoid_unnecessary_containers
    # 异步方法不要直接返回void 返回Future<void>
    - avoid_void_async
    # 避免使用await修饰非Future,null可以作为特殊情况
    - await_only_futures
    # StreamSubscription一定要记得cancel
    - cancel_subscriptions
    # 不要将可空值? as成不可空值
    - cast_nullable_to_non_nullable
    # 使用集合的方法不要传入与集合类型不相符的参数
    - collection_methods_unrelated_type
    # 依赖的库应该在dependcies中指定版本号
    - depend_on_referenced_packages
    # 使用有效的正则语法
    - valid_regexps
    # 条件导入中,不要使用不存在的路径
    - conditional_uri_does_not_exist
    # 重写==运算符时要同步重写hashCode
    - hash_and_equals
    # Switch case 中case不要重复
    - no_duplicate_case_values
    # 不要将变量赋值给自身
    - no_self_assignments
    # createState()中不要写逻辑代码
    - no_logic_in_create_state
    # 不要对可能为空的对象使用 !
    - null_check_on_nullable_type_parameter
    # 不要覆盖父类的属性
    - overridden_fields
    # 使用const来修饰具有const构造方法产生的对象
    - prefer_const_constructors
    # 对于不可变的类,需要使用const来修饰构造方法
    - prefer_const_constructors_in_immutables
    # 使用const 作为 @immutable 类的初始化参数
    - prefer_const_literals_to_create_immutables
    # 不要在可能使用的闭包中传入null
    - null_closures
    # 未在定义的时候初始化的变量应该指明类型
    - prefer_typing_uninitialized_variables
    # 布局添加空白使用sizebox代替container,sizeBox更轻量,而且可以用const
    - sized_box_for_whitespace
    # 复写类的==方法时,一定要判断入参的类型,以防止传入null等
    - test_types_in_equals
    # try catch final的 finally中不应该抛出error
    - throw_in_finally
    # 为空判断赋值中不要使用null: x ??= null 
    - unnecessary_null_aware_assignments
    # 不使用不安全的html api
    - unsafe_html
    # 不要再函数入口处定义无法执行到的代码
    - unreachable_from_main
    # 仅设置颜色时使用ColoredBox组件 代替Container
    - use_colored_box
    # 仅在同步方法中使用BuildContext,异步方法中可能context已销毁
    - use_build_context_synchronously
    # 避免使用无意义的代码,无用的语句应及时删除
    - unnecessary_statements

    # 控制语句的控制体总是新起一行 
    - always_put_control_body_on_new_line
    # 避免在条件表达式中使用bool值 condition ? true : boolExpression
    - avoid_bool_literals_in_conditional_expressions   
    # 不要使用空的else语句
    - avoid_empty_else
    # 不要对未标记为@immutable的类覆盖==和hashcode方法
    - avoid_equals_and_hash_code_on_mutable_classes
    # 通过双引号来消除字符串中的转义字符
    - avoid_escaping_inner_quotes
    # 在常量类中避免进行初始化
    - avoid_field_initializers_in_const_classes
    # 不要显式的初始化一个变量为null
    - avoid_init_to_null
    # 重写==运算符时不要用来判断是否为null, 由于null是一种特殊类型,没有类可以与它等效。因此,检查另一个实例是否为空是多余的
    - avoid_null_checks_in_equality_operators
    # 不要重复设置参数的值
    - avoid_redundant_argument_values
    # 相对引用中不使用lib/
    - avoid_relative_lib_imports
    # 不要用级联表达式调用方法
    - avoid_single_cascade_in_expression_statements
    # 有一些dart:io库中的方法异步方法比同步方法慢很多,尽量使用同步方法
    - avoid_slow_async_io
    # 不要在初始化方法中定义没必要的参数
    - avoid_unused_constructor_parameters
    # 定义extensions 使用大驼峰命名
    - camel_case_extensions
    # 定义类名使用首字母大写驼峰
    - camel_case_types
    # 只有library文件的起始行可使用文档注释 
    - dangling_library_doc_comments
    # 对于dart:的引用排序应该在其他引用之前
    - directives_ordering
    # try catch的catch不要传空block,如果有意这么做,需要添加注释ignored,或使用_参数
    - empty_catches
    # 文件结尾处留一行空行
    - eol_at_end_of_file
    # 文件名使用 _下划线命名规则
    - file_names
    # 使用flutter风格的TODO
    - flutter_style_todos
    # 当函数作为函数的参数时,显示的调用参数的call方法
    - implicit_call_tearoffs
    # 不要隐式的重新打开类
    - implicit_reopen
    # 多行的multilineString使用时要另起一行
    - leading_newlines_in_multiline_strings
    # 将库注释附加到库指令上,而不是附加到其他库级元素上。
    - library_annotations
    # library名称使用 _下划线命名规则
    - library_names
    # 引用库的前缀应该遵循小写字母带下划线格式
    - library_prefixes
    # 在换行连接字符串的时候应该加入空格
    - missing_whitespace_between_adjacent_strings
    # import库使用as时 不要用下划线开头
    - no_leading_underscores_for_library_prefixes 
    # 不要使用通配符参数或变量
    - no_wildcard_variable_uses
    # 非常量命名使用小驼峰
    - non_constant_identifier_names
    # 只抛出 Exception 或者 Error或者他们子类的异常
    - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al
    # package_names使用 小写 _下划线命名规则
    - package_names
    # 用包名和以点分隔的路径作为库名的前缀 例子:library my_package.other;
    - package_prefixed_library_names
    # 不要用+连接字符串,相邻字符串会自动连接
    - prefer_adjacent_string_concatenation
    # 不要在构造函数体内执行 assert
    - prefer_asserts_in_initializer_lists
    # 使用集合字面量
    - prefer_collection_literals
    # 使用 ??= 代替判断 name == null
    - prefer_conditional_assignment
    # 通过遍历来创建map时最好使用for循环
    - prefer_for_elements_to_map_fromIterable
    # 遍历中需要调用function时,最好用foreach
    - prefer_foreach
    # 尽可能的使用函数声明
    - prefer_function_declarations_over_variables
    # 使用泛型类型的函数别名 typedef F = void Function();
    - prefer_generic_function_type_aliases
    # 使用??来作为判空进行赋值操作 v = a ?? b;
    - prefer_if_null_operators
    # 在列表初始化时就尽量声明全部参数,而不是后续使用add和addAll
    - prefer_inlined_adds
    # 使用变量来组合字符串而不是+ 例:'Hello, ${person.name} from ${person.city}.'
    - prefer_interpolation_to_compose_strings
    # 使用is!而不是反is
    - prefer_is_not_operator
    # 使用whereType按照类型过滤集合
    - prefer_iterable_whereType
    # 使用mixin来混入
    - prefer_mixin
    # 使用?.来判空 而不是if
    - prefer_null_aware_operators
    # 使用单引号
    - prefer_single_quotes 
    # 尽量使用扩展运算符 ..
    - prefer_spread_collections
    # 在deprecation中写明信息
    - provide_deprecation_message
    # 使用///来作为文档注释
    - slash_for_doc_comments
    # 不要在字符串中使用不必要的大括号
    - unnecessary_brace_in_string_interps
    # 不使用没必要的break,尤其在Switch中
    - unnecessary_breaks
    # 不必要的构造函数名称
    - unnecessary_constructor_name
    # 不使用没必要的getter和setter
    - unnecessary_getters_setters
    # 避免使用库指令,除非它们有文档注释或注解。
    - unnecessary_library_directive
    # 没必要在可为空的扩展上使用?.操作符
    - unnecessary_null_aware_operator_on_extension_on_nullable
    # 不要使用没必要的null检测
    - unnecessary_null_checks
    # 不要使用没必要的overrides
    - unnecessary_overrides
    # 不使用没必要的小括号 a = (b);
    - unnecessary_parenthesis
    # string中没必要使用 \ 
    - unnecessary_string_escapes
    # string中不使用不必要的转化: String message; String o = '$message';
    - unnecessary_string_interpolations
    # 不要使用没必要的this
    - unnecessary_this
    # 不使用没必要的toList()扩展
    - unnecessary_to_list_in_spreads
    # 不要使用==来比较两个无关的类
    - unrelated_type_equality_checks
    # 使用枚举代替class
    - use_enums
    # 使用8位16进制数表示颜色 如:(0xFFFFFFFF)
    - use_full_hex_values_for_flutter_colors
    # 函数参数使用泛型语法  Iterable<T> where(bool Function(T) predicate) {}
    - use_function_type_syntax_for_parameters
    # 使用isEven或者isodd来判断奇偶
    - use_is_even_rather_than_modulo
    # 使用系统已经定义好的常量值
    - use_named_constants
    # 使用raw string来避免使用转义符 如:var s = r'A string with only \ and $';
    - use_raw_strings
    # 使用rethrow再次抛出异常
    - use_rethrow_when_possible
    # 在part of 关键字中使用String 如: part of '../../my_library.dart';
    - use_string_in_part_of_directives
    # 不要给void类型的变量赋值
    - void_checks
    # 不使用没必要的late
    - unnecessary_late
    # 类中的deprecated应该保持一致
    - deprecated_consistency
    # 使用setter点方法修改属性而不是直接调用方法
    - use_setters_to_change_properties
    # 尽量使用super初始化参数
    - use_super_parameters
    # 使用??来将null转换为布尔值 if (nullableBool ?? false){}
    - use_if_null_to_convert_nulls_to_bools
    # 不要使用重复的const
    - unnecessary_const
    # 不使用没必要的new 创建实例不需要用new
    - unnecessary_new
    # 对于初始化非空的final变量不要定义为可空类型
    - unnecessary_nullable_for_final_variable_declarations
    # set方法不要带返回值
    - avoid_return_types_on_setters
    # 总是在控制流中使用大括号来括住控制语句
    - curly_braces_in_flow_control_structures
    # 阻止条件控制流进入finally语句中
    - control_flow_in_finally
    # 使用方法isempty而不是查询它的长度
    - prefer_is_empty
    # 尽可能多用isNotEmpty代替判断length
    - prefer_is_not_empty
    # boolean值之间不要比较: if(isTrue == true) 改为if(isTrue)
    - no_literal_bool_comparisons
    # 判断Type不要使用ToString()
    - avoid_type_to_string
    # 在for each中不可变值使用final
    - prefer_final_in_for_each
    # if后不要使用空语句
    - empty_statements
    # 尽量使用final来设置变量
    - prefer_final_locals
    # 在String和List中优先使用contains 代替indexOf
    - prefer_contains
    # 尽量使用if else 而不使用三元运算符
    - prefer_if_elements_to_conditional_expressions
    # 私有属性设置为final
    - prefer_final_fields
    # 在??操作符后面避免使用null
    - unnecessary_null_in_if_null_operators
    # 判断语句中只进行真假的判断,而不要进行赋值等各种其他操作
    - literal_only_boolean_expressions
    # 公用API要提供注释
    - package_api_docs
    # 不要调用原始类型的转换方法: int a = 1; a.toInt();
    - noop_primitive_operations
    # 不使用不必要的await
    - unnecessary_await_in_return
    # 尽量使用const声明变量
    - prefer_const_declarations
    # get方法不要返回自身
    - recursive_getters
    # 重写的方法不要修改参数名
    - avoid_renaming_method_parameters
    # Switch中不要使用无效的case
    - invalid_case_patterns
    # 不要在库对外开放的API中使用私有类型.
    - library_private_types_in_public_api
    # 不要在list中连接字符串: ['a', 'b'+ 'c', 'd']
    - no_adjacent_strings_in_list
    # 尽可能使用初始化来给类属性赋值
    - prefer_initializing_formals
    # 声明参数名不要和已存在的类型相同
    - avoid_types_as_parameter_names
    # 在void可以使用的时候,不要使用NULL
    - prefer_void_to_null
    # 使用SizedBox.shrink(...) 和 SizedBox.expand(...)代替空的 SizedBox
    - sized_box_shrink_expand
    # 初始化参数如果是类中的属性不需要指定类型
    - type_init_formals
    # 构造函数不要使用大括号来括住空的初始化方法
    - empty_constructor_bodies
    # 严格指定参数初始化类型
    - tighten_type_of_initializing_formals
    # 使用late来定义非空的私有变量 【需讨论确定,flutter2中担心不合规使用导致bug,禁用了late关键字】
    - use_late_for_private_fields_and_variables


    # 按照字母顺序排序 例如: import 'a.dart' show A, B hide C, D;
    - combinators_ordering
    # 避免检测类型为int或double,检测num if(x is num), 
    - avoid_double_and_int_checks 
    # 不要只实现setters而不实现getters 
    - avoid_setters_without_getters
    # 不要使用foreach来进行遍历(foreach中逻辑不如for in 清晰且不能使用await) 
    - avoid_function_literals_in_foreach_calls
    # switch-case中应该列出case的所有可能 
    - exhaustive_cases
    # 不要引用其他package的lib/src文件夹下的文件 
    - implementation_imports
    # 在switch-case中不要使用default 
    - no_default_cases
    # 命名本地变量不要以下划线开头 
    - no_leading_underscores_for_local_identifiers
    # 引用同一模块的头文件时,使用相对路径 
    - prefer_relative_imports
    # pubspec.yaml使用安全的链接url  
    - secure_pubspec_urls
    # 在widget创建过程中将child属性放在最后 
    - sort_child_properties_last
    # 类中的构造方法放在第一位 
    - sort_constructors_first
    # 未命名的构造方法放在第一位
    - sort_unnamed_constructors_first
    # 不要对类型字面量使用常量模式 
    - type_literal_in_constant_pattern
    # 使用throwsA 代替fail() 
    - use_test_throws_matchers

参考:

dart.cn/tools/analy…

github.com/flutter/pac…