写在前面
作为 Flutter 开发的基础语言,Dart 融合了 Java 的类型安全和 JavaScript 的灵活性。如果您已经掌握了 Java 或 JavaScript,那么学习 Dart 将会非常轻松。本文将通过实例和对比的方式,帮助您快速掌握 Dart 的核心特性。
为什么选择 Dart?
在开始学习之前,让我们先了解为什么要选择 Dart:
-
优秀的类型系统
- 支持静态类型检查
- 类型推断让代码更简洁
- 空安全特性避免空指针异常
-
现代化的语言特性
- 支持异步编程(async/await)
- 强大的集合操作 API
- Mixin 和扩展方法支持
-
跨平台能力
- Web 开发(编译成 JavaScript)
- 移动应用开发(通过 Flutter)
- 服务端开发
变量和数据类型
Dart 是一种静态类型语言,支持显式类型声明和类型推断。以下是几种常见的变量声明方式:
1. 变量声明的不同方式
-
显式类型声明:明确指定变量的类型。
dartString name = 'Flutter'; // 显式声明为 String 类型
-
类型推断 :使用
var
关键字,编译器会根据赋值自动推断类型。dartvar age = 25; // 推断为 int 类型
-
动态类型 :使用
dynamic
关键字,允许变量在运行时改变类型。dartdynamic height = 1.75; // 动态类型,可以随时改变类型 height = "tall"; // 运行时可以改变类型
-
常量 :使用
final
和const
关键字声明不可变的变量。dartfinal version = '3.0.0'; // 运行时常量,只能赋值一次 const PI = 3.14159; // 编译时常量,必须在编译时确定
2. 类型推断的使用场景
-
集合类型 :Dart 支持多种集合类型,如
List
和Map
,并且可以通过类型推断简化声明。dartvar 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
。dartString? nullableName; int? age;
2. 延迟初始化
-
使用
late
关键字延迟初始化变量,确保在首次访问时才进行初始化。dartlate String name;
注意:延迟初始化变量必须在声明时提供默认值,否则会报错。
3. 空值检查
-
使用
??
运算符提供默认值。dartvoid printName(String? name) { print(name ?? 'Unknown'); // 如果 name 为 null,则输出 'Unknown' }
-
使用
?.
安全调用操作符。dartprint(name?.toUpperCase()); // 如果 name 为 null,则不会调用 toUpperCase()
-
使用
!
断言非空。dartif (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. 基本函数
-
返回一个整数的简单加法函数。
dartint add(int a, int b) { return a + b; }
2. 箭头函数
-
简洁的单行函数定义。
dartvoid printHello() => print('Hello');
3. 可选参数
-
使用方括号
[ ]
定义可选参数,默认值可以用??
提供。dartString sayHello([String? name]) { return 'Hello ${name ?? "Guest"}'; // 如果 name 为 null,则使用 "Guest" }
4. 命名参数
-
使用花括号
{ }
定义命名参数,默认值可以用??
提供。dartString greet({String name = 'Guest', int age = 0}) { return 'Hello $name, you are $age years old.'; }
异步编程进阶
Dart 支持异步编程,通过 Future
和 Stream
实现非阻塞操作。
1. Future 使用
-
使用
async
和await
关键字简化异步代码。dartFuture<String> fetchUserData() async { try { final response = await dio.get('/api/user'); return response.data['name']; } catch (e) { return 'Error: $e'; } }
2. Stream 使用
-
使用
async*
和yield
创建流。dartStream<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。dartStreamBuilder<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 是一种组合类功能的方式,类似于多继承。
dartmixin Logger { void log(String message) { print('LOG: $message'); } } class UserService with Logger { void createUser() { log('Creating user...'); // 创建用户逻辑 } }
2. 扩展方法
-
扩展方法允许为现有类添加新方法,而无需修改其源代码。
dartextension 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 开发之旅有所帮助。如果觉得有用,请点赞转发,您的支持是我持续创作的动力!