Flutter项目开发规范

412 阅读3分钟

命名规范

遵循Dart的官方风格指南Dart官方风格指南,确保代码与社区推荐的格式保持一致。

注释与文档

  • 使用三斜杠(///)编写文档注释来描述公共 API 的功能、用法和约束。
  • 对于复杂的逻辑和算法,使用双斜杠(//)添加行内注释,解释代码的目的和实现方式。
  • 保持注释简洁明了,并及时更新以保持与代码同步。
class TestClass {
  /// 用户名
  String? username;

  /// 邮箱
  String? email;

  /// id
  int? id;

  /// 年龄
  int _age = 0;

  /// 获取年龄
  ///
  /// 返回值:年龄
  int get age => _age;

  /// 设置年龄
  ///
  /// [value] 要设置的年龄值
  set age(int value) {
    if (value < 0) {
      throw ArgumentError('age 不能为负数');
    }
    _age = value;
  }

  /// 创建TestClass对象
  ///
  /// [username] 用户名
  /// [email] 邮箱
  /// [id] id
  TestClass(this.username, this.email, this.id);

  /// 将对象转换为包含属性键值对的 Map。
  ///
  /// 返回值:包含属性键值对的 Map。
  Map<String, dynamic> toMap() {
    return {
      "username": username ?? "",
      "email": email ?? "",
      "id": id ?? 0,
    };
  }

  /// 删除[路径]处的文件。
  ///
  /// [path] 文件路径
  /// 如果找不到文件,则抛出[IOError]。抛出一个
  /// [PermissionError],如果文件存在但无法删除
  void delete(String path) {}

  /// 计算两个整数的和。
  ///
  /// [a]:第一个整数
  /// [b]:第二个整数
  ///
  /// 返回值:两个整数的和
  int calculateSum(int a, int b) {
    return a + b;
  }
}

布局代码规范

// 错误
// 未用const修饰, 逗号换行
@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(
        title: Text("test"),
      ),
      extendBody: true,
      body: Column(children: [
        Spacer(),
        Container(
          margin: EdgeInsets.all(10),
          child: Center(child: TextField()),
        ),
        Spacer()
      ]));
}

// 正确
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text("test"),
    ),
    extendBody: true,
    body: Column(
      children: [
        const Spacer(),
        Container(
          margin: const EdgeInsets.all(10),
          child: const Center(
            child: TextField(),
          ),
        ),
        const Spacer(),
      ],
    ),
  );
}

可选值处理

String? optionalValue;

// 错误
// 未进行判空处理
if (optionalValue!.isNotEmpty) {
  print(optionalValue.length);
}

// 正确
if (optionalValue != null && optionalValue.isNotEmpty) {
  print(optionalValue.length);
}

异常错误处理

  • 使用 assert 函数检查开发期间的错误条件。
  • 使用 try-catch 语句处理可能引发异常的代码,并使用 finally 子句清理资源。
  • 在捕获异常时,通过日志记录或显示错误信息以便进行调试。
void divide(int dividend, int divisor) {
  assert(divisor != 0, '除数不能为零');
  try {
    // 执行除法操作
    double result = dividend / divisor;
    print('结果:$result');
  } catch (e) {
    print('发生异常:$e');
  } finally {
    // 清理操作
    print('执行清理操作');
  }
}

void test() {
  try {
    // 可能抛出异常的代码
  } on ExceptionType1 catch (e) {
    // 处理 ExceptionType1 类型的异常
  } on ExceptionType2 catch (e) {
    // 处理 ExceptionType2 类型的异常
  } catch (e) {
    // 处理其他类型的异常
  }
}

对于可能导致异步操作的函数,使用asyncawait关键字进行异步编程,并使用try-catch语句捕获和处理可能的异常

Future<void> fetchData() async {
  try {
    // 异步操作的代码逻辑
    final response = await http.get('https://api.example.com/data');
    // 处理响应数据
  } catch (e) {
    // 异常处理逻辑
    print('发生异常:$e');
  }
}

后端返回数据处理

  • 不要相信后端返回的数据
  • 不要相信后端返回的数据
  • 不要相信后端返回的数据
  • 后端返回的JSON数据必须转换成模型
// 错误
// 字段类型可能为空,类型可能不匹配,会引发异常
void test() async {
    Map map = await fetchData();
    String name = map["name"];
    int age = map["age"];
    int id = map["id"];
}

// 正确
void test() async {
  Map map = await fetchData();
  final model = Model.fromMap(map);
  print(model.name);
  print(model.age);
  print(model.id);
}

class Model {
  String? name;
  int? age;
  int? id;

  Model.fromMap(Map map) {
    name = _parseValue<String>(map["name"]);
    age = _parseValue<int>(map["age"]);
    id = _parseValue<int>(map["id"]);
  }

  T? _parseValue<T>(dynamic value) {
    if (value is T) {
      return value;
    }
    return null;
  }
}

三木运算符使用

在 Dart 中,三木运算符 (ternary operator) 可以用于简化代码并减少 if-else 语句的使用。它的形式为 condition ? expression_if_true : expression_if_false

使用规范

  • 三木运算符的主要目的是减少代码量,并使代码更紧凑。因此,在选择使用时,考虑是否可以替代 if-else 语句以提高代码的简洁性
  • 过度使用三木运算符可能导致代码难以阅读。请避免在一个表达式中使用多个三木运算符,以确保代码可读性
// 错误  
void test() {  
  int a = 10;  
  int b = 20;  
  int c = 30;  
  final status = a == 1 ? 6 : b == 2 ? 3 : c == 30 ? 2 : 40;  
}

// 正确  
void test() {  
  int a = 10;  
  int b = 20;  
  int c = 30;  
  var status = 40;  
  if (a == 1) {  
    status = 6;  
  } else if (b == 2) {  
    status = 3;  
  } else if (c == 30) {  
    status = 2;  
  }  
}