【Flutter入门】2. 快速掌握Dart语言 - 从 Java、JavaScript 转型必看

写在前面

作为 Flutter 开发的基础语言,Dart 融合了 Java 的类型安全和 JavaScript 的灵活性。如果您已经掌握了 Java 或 JavaScript,那么学习 Dart 将会非常轻松。本文将通过实例和对比的方式,帮助您快速掌握 Dart 的核心特性。

为什么选择 Dart?

在开始学习之前,让我们先了解为什么要选择 Dart:

  1. 优秀的类型系统

    • 支持静态类型检查
    • 类型推断让代码更简洁
    • 空安全特性避免空指针异常
  2. 现代化的语言特性

    • 支持异步编程(async/await)
    • 强大的集合操作 API
    • Mixin 和扩展方法支持
  3. 跨平台能力

    • Web 开发(编译成 JavaScript)
    • 移动应用开发(通过 Flutter)
    • 服务端开发

变量和数据类型

Dart 是一种静态类型语言,支持显式类型声明和类型推断。以下是几种常见的变量声明方式:

1. 变量声明的不同方式

  • 显式类型声明:明确指定变量的类型。

    dart 复制代码
    String name = 'Flutter'; // 显式声明为 String 类型
  • 类型推断 :使用 var 关键字,编译器会根据赋值自动推断类型。

    dart 复制代码
    var age = 25; // 推断为 int 类型
  • 动态类型 :使用 dynamic 关键字,允许变量在运行时改变类型。

    dart 复制代码
    dynamic height = 1.75; // 动态类型,可以随时改变类型
    height = "tall"; // 运行时可以改变类型
  • 常量 :使用 finalconst 关键字声明不可变的变量。

    dart 复制代码
    final version = '3.0.0'; // 运行时常量,只能赋值一次
    const PI = 3.14159; // 编译时常量,必须在编译时确定

2. 类型推断的使用场景

  • 集合类型 :Dart 支持多种集合类型,如 ListMap,并且可以通过类型推断简化声明。

    dart 复制代码
    var list = ['a', 'b', 'c']; // List<String>
    var map = {1: 'one', 2: 'two'}; // Map<int, String>

3. 类型安全的重要性

Dart 是强类型语言,确保代码的类型安全非常重要。例如:

dart 复制代码
void example() {
  var name = 'Flutter';
  // name = 42; // 编译错误:不能将 int 赋值给 String 类型的变量
}

空安全特性

Dart 引入了空安全(Null Safety),以防止空指针异常。以下是几种处理可空类型的常见方法:

1. 可空类型

  • 使用 ? 表示变量可以为 null

    dart 复制代码
    String? nullableName;
    int? age;

2. 延迟初始化

  • 使用 late 关键字延迟初始化变量,确保在首次访问时才进行初始化。

    dart 复制代码
    late String name;

    注意:延迟初始化变量必须在声明时提供默认值,否则会报错。

3. 空值检查

  • 使用 ?? 运算符提供默认值。

    dart 复制代码
    void printName(String? name) {
      print(name ?? 'Unknown'); // 如果 name 为 null,则输出 'Unknown'
    }
  • 使用 ?. 安全调用操作符。

    dart 复制代码
    print(name?.toUpperCase()); // 如果 name 为 null,则不会调用 toUpperCase()
  • 使用 ! 断言非空。

    dart 复制代码
    if (name != null) {
      print(name!.toUpperCase()); // 断言 name 不为 null
    }

4. 应用示例

dart 复制代码
// 实际应用场景示例
class User {
  final String name;
  final int? age; // 可选年龄
  late final String email; // 延迟初始化邮箱

  User(this.name, {this.age}) {
    // 延迟初始化示例
    email = fetchEmailFromDatabase(); // 从数据库获取邮箱
  }

  // 空安全处理示例
  String getDisplayName() {
    return age != null ? '$name ($age岁)' : name;
  }
}

函数定义

Dart 支持多种函数定义方式,包括普通函数、箭头函数、带参数的函数等。

1. 基本函数

  • 返回一个整数的简单加法函数。

    dart 复制代码
    int add(int a, int b) {
      return a + b;
    }

2. 箭头函数

  • 简洁的单行函数定义。

    dart 复制代码
    void printHello() => print('Hello');

3. 可选参数

  • 使用方括号 [ ] 定义可选参数,默认值可以用 ?? 提供。

    dart 复制代码
    String sayHello([String? name]) {
      return 'Hello ${name ?? "Guest"}'; // 如果 name 为 null,则使用 "Guest"
    }

4. 命名参数

  • 使用花括号 { } 定义命名参数,默认值可以用 ?? 提供。

    dart 复制代码
    String greet({String name = 'Guest', int age = 0}) {
      return 'Hello $name, you are $age years old.';
    }

异步编程进阶

Dart 支持异步编程,通过 FutureStream 实现非阻塞操作。

1. Future 使用

  • 使用 asyncawait 关键字简化异步代码。

    dart 复制代码
    Future<String> fetchUserData() async {
      try {
        final response = await dio.get('/api/user');
        return response.data['name'];
      } catch (e) {
        return 'Error: $e';
      }
    }

2. Stream 使用

  • 使用 async*yield 创建流。

    dart 复制代码
    Stream<int> countStream(int max) async* {
      for (int i = 1; i <= max; i++) {
        await Future.delayed(Duration(seconds: 1));
        yield i;
      }
    }

3. 使用 StreamBuilder

  • 在 Flutter 中使用 StreamBuilder 构建响应式 UI。

    dart 复制代码
    StreamBuilder<int>(
      stream: countStream(10),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text('Count: ${snapshot.data}');
        }
        return CircularProgressIndicator();
      },
    )

4. 实际网络请求示例

dart 复制代码
// 实际网络请求示例
Future<List<User>> fetchUsers() async {
  try {
    final response = await http.get(Uri.parse('https://api.example.com/users'));
    if (response.statusCode == 200) {
      final List<dynamic> data = jsonDecode(response.body);
      return data.map((json) => User.fromJson(json)).toList();
    } else {
      throw Exception('加载用户数据失败');
    }
  } catch (e) {
    print('错误:$e');
    return [];
  }
}

// Stream 实际应用示例
Stream<int> countdown(int seconds) async* {
  for (var i = seconds; i >= 0; i--) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

// 使用示例
void main() async {
  await for (final count in countdown(5)) {
    print('倒计时:$count');
  }
  print('完成!');
}

Mixin 和扩展

Dart 支持 Mixin 和扩展方法,用于增强类的功能。

1. Mixin 定义

  • Mixin 是一种组合类功能的方式,类似于多继承。

    dart 复制代码
    mixin Logger {
      void log(String message) {
        print('LOG: $message');
      }
    }
    
    class UserService with Logger {
      void createUser() {
        log('Creating user...');
        // 创建用户逻辑
      }
    }

2. 扩展方法

  • 扩展方法允许为现有类添加新方法,而无需修改其源代码。

    dart 复制代码
    extension StringExtension on String {
      String capitalize() {
        return "${this[0].toUpperCase()}${this.substring(1)}";
      }
    }
    
    void main() {
      print('hello'.capitalize()); // 输出: Hello
    }

与 Java/JavaScript 的对比

Dart 融合了 Java 的静态类型特性和 JavaScript 的灵活性,下面是主要区别:

1. 变量声明对比

dart 复制代码
// Dart
var name = 'Flutter';
String title = 'Hello';
dynamic value = 42;

// Java
String name = "Java";
var title = "Hello"; // Java 10+ 支持
Object value = 42;

// JavaScript
let name = 'JavaScript';
const title = 'Hello';
var value = 42;

2. 函数定义对比

dart 复制代码
// Dart
void hello(String name) => print('Hello $name');
int add(int a, {int b = 0}) => a + b;

// Java
public void hello(String name) {
    System.out.println("Hello " + name);
}
public int add(int a, int b) {
    return a + b;
}

// JavaScript
const hello = (name) => console.log(`Hello ${name}`);
const add = (a, b = 0) => a + b;

3. 类定义对比

dart 复制代码
// Dart
class Person {
  final String name;
  int? age;

  Person(this.name, {this.age}); // 简洁的构造函数

  void sayHello() => print('Hello, I am $name');
}

// Java
public class Person {
    private final String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void sayHello() {
        System.out.println("Hello, I am " + name);
    }
}

// JavaScript
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    sayHello() {
        console.log(`Hello, I am ${this.name}`);
    }
}

4. 异步编程对比

dart 复制代码
// Dart
Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return 'Data';
}

// Java (使用 CompletableFuture)
CompletableFuture<String> fetchData() {
    return CompletableFuture.supplyAsync(() -> {
        Thread.sleep(1000);
        return "Data";
    });
}

// JavaScript
async function fetchData() {
    await new Promise(resolve => setTimeout(resolve, 1000));
    return 'Data';
}

5. 主要特性对比

特性 Dart Java JavaScript
类型系统 静态类型(支持类型推断) 静态类型 动态类型
空安全 内置支持 需要注解(@Nullable) 无内置支持
函数式编程 支持 部分支持(Java 8+) 完全支持
异步编程 async/await CompletableFuture async/await
混入(Mixin) 支持 不支持 部分支持

6. 集合操作对比

dart 复制代码
// Dart
final list = [1, 2, 3];
final doubled = list.map((e) => e * 2).toList();
final sum = list.reduce((a, b) => a + b);

// Java
List<Integer> list = Arrays.asList(1, 2, 3);
List<Integer> doubled = list.stream()
    .map(e -> e * 2)
    .collect(Collectors.toList());
int sum = list.stream().reduce(0, Integer::sum);

// JavaScript
const list = [1, 2, 3];
const doubled = list.map(e => e * 2);
const sum = list.reduce((a, b) => a + b);

实战技巧

在实际开发中,以下是一些常用的 Dart 编程技巧:

1. 字符串处理技巧

dart 复制代码
// 1. 字符串模板使用
final name = 'Dart';
print('Hello $name'); // 简单变量
print('1 + 1 = ${1 + 1}'); // 表达式

// 2. 多行字符串
final multiLine = '''
  这是第一行
  这是第二行
  这是第三行
''';

// 3. 字符串拼接优化
final items = ['A', 'B', 'C'];
// ❌ 不推荐
String result = '';
for (var item in items) {
  result += item + ', ';
}

// ✅ 推荐
final result = items.join(', ');

2. 集合操作技巧

dart 复制代码
// 1. 级联操作符
final button = Button()
  ..color = Colors.blue
  ..width = 100
  ..height = 50
  ..onPressed = () => print('clicked');

// 2. 集合转换和过滤
final numbers = [1, 2, 3, 4, 5];
// 链式操作
final result = numbers
    .where((n) => n.isEven)        // 过滤偶数
    .map((n) => n * 2)             // 每个数乘2
    .fold(0, (sum, n) => sum + n); // 求和

// 3. 集合展开操作符
final list1 = [1, 2, 3];
final list2 = [4, 5, 6];
final combined = [...list1, ...list2]; // [1, 2, 3, 4, 5, 6]

3. 异步操作技巧

dart 复制代码
// 1. 并发请求处理
Future<void> fetchMultipleData() async {
  final results = await Future.wait([
    fetchUser(),
    fetchOrders(),
    fetchProducts(),
  ]);

  final user = results[0];
  final orders = results[1];
  final products = results[2];
}

// 2. 超时处理
Future<String> fetchWithTimeout() async {
  try {
    return await fetchData().timeout(
      Duration(seconds: 5),
      onTimeout: () => throw TimeoutException('请求超时'),
    );
  } on TimeoutException {
    return '默认数据';
  }
}

// 3. 重试机制
Future<T> retry<T>(
  Future<T> Function() fn, {
  int maxAttempts = 3,
  Duration delay = const Duration(seconds: 1),
}) async {
  try {
    return await fn();
  } catch (e) {
    if (maxAttempts > 1) {
      await Future.delayed(delay);
      return retry(fn, maxAttempts: maxAttempts - 1, delay: delay);
    }
    rethrow;
  }
}

常见陷阱和解决方案

1. 空安全相关陷阱

dart 复制代码
// 1. late 变量初始化陷阱
class User {
  // ❌ 危险:可能导致运行时错误
  late String name;

  // ✅ 安全:提供默认值或在构造函数中初始化
  late final String name;
  User(this.name);
}

// 2. 强制非空断言陷阱
// ❌ 危险:可能抛出异常
void processName(String? name) {
  print(name!.toUpperCase());
}

// ✅ 安全:使用空值检查
void processName(String? name) {
  if (name != null) {
    print(name.toUpperCase());
  }
}

// 3. 集合空安全处理
// ❌ 不安全
List<String>? names;
final firstItem = names![0];

// ✅ 安全
List<String>? names;
final firstItem = names?.firstOrNull ?? 'default';

2. 异步编程陷阱

dart 复制代码
// 1. Future 的错误处理
// ❌ 错误:遗漏错误处理
void fetchData() async {
  final data = await api.getData();
  processData(data);
}

// ✅ 正确:添加错误处理
void fetchData() async {
  try {
    final data = await api.getData();
    processData(data);
  } catch (e) {
    print('获取数据失败: $e');
    // 错误恢复逻辑
  }
}

// 2. Stream 订阅管理
class DataService {
  StreamSubscription? _subscription;

  // ❌ 错误:没有取消订阅
  void startListening() {
    _subscription = stream.listen((_) {});
  }

  // ✅ 正确:在适当时机取消订阅
  void dispose() {
    _subscription?.cancel();
    _subscription = null;
  }
}

3. 性能相关陷阱

dart 复制代码
// 1. 列表操作优化
// ❌ 性能不佳
void processItems(List<String> items) {
  for (var i = 0; i < items.length; i++) {
    print(items[i]);
  }
}

// ✅ 性能更好
void processItems(List<String> items) {
  for (final item in items) {
    print(item);
  }
}

// 2. 内存泄漏防范
class Controller {
  Timer? _timer;

  // ❌ 可能导致内存泄漏
  void startTimer() {
    _timer = Timer.periodic(Duration(seconds: 1), (_) {
      // 处理逻辑
    });
  }

  // ✅ 正确处理资源释放
  void dispose() {
    _timer?.cancel();
    _timer = null;
  }
}

4. 状态管理陷阱

dart 复制代码
// 1. 状态更新
// ❌ 不推荐:直接修改状态
class Counter {
  int count = 0;
  void increment() => count++;
}

// ✅ 推荐:使用不可变状态
class Counter {
  final int count;
  Counter(this.count);

  Counter increment() => Counter(count + 1);
}

// 2. 对象比较
// ❌ 可能导致不必要的重建
class User {
  final String name;
  User(this.name);
}

// ✅ 实现相等性比较
class User {
  final String name;
  User(this.name);

  @override
  bool operator ==(Object other) =>
    identical(this, other) ||
    other is User &&
    runtimeType == other.runtimeType &&
    name == other.name;

  @override
  int get hashCode => name.hashCode;
}

希望这篇文章对您的 Flutter 开发之旅有所帮助。如果觉得有用,请点赞转发,您的支持是我持续创作的动力!

参考资源

相关推荐
阿笑带你学前端1 小时前
Flutter本地通知系统:记账提醒的深度实现
前端·flutter
孤鸿玉20 小时前
Fluter InteractiveViewer 与ScrollView滑动冲突问题解决
flutter
叽哥1 天前
Flutter Riverpod上手指南
android·flutter·ios
BG2 天前
Flutter 简仿Excel表格组件介绍
flutter
zhangmeng2 天前
FlutterBoost在iOS26真机运行崩溃问题
flutter·app·swift
恋猫de小郭2 天前
对于普通程序员来说 AI 是什么?AI 究竟用的是什么?
前端·flutter·ai编程
卡尔特斯2 天前
Flutter A GlobalKey was used multipletimes inside one widget'schild list.The ...
flutter
w_y_fan2 天前
Flutter 滚动组件总结
前端·flutter
醉过才知酒浓2 天前
Flutter Getx 的页面传参
flutter
火柴就是我3 天前
flutter 之真手势冲突处理
android·flutter