Skip to content

🎯 Flutter 从零到一(一):Dart 语言基础 — Flutter 的敲门砖

系列导读:这是「Flutter 从零到一」系列的第 1 篇。即使你从未写过一行 Dart 代码, 读完本文也能掌握 Flutter 开发所需的全部语言基础。

本文目标:掌握 Dart 的变量、类型、函数、面向对象、集合、异步编程六大核心模块, 每个知识点都附带可运行的代码示例。


📊 Dart 语言速览

维度说明
🏢 出品方Google(2011 年发布)
🎯 定位客户端优化语言,Flutter 唯一开发语言
📝 类型系统强类型 + 类型推断 + 空安全
🔄 编译方式JIT(开发热重载)+ AOT(发布高性能)
🌐 运行平台移动端 / Web / 桌面 / 服务端
📦 包管理器pub.dev

🔤 1. 变量与类型

变量声明

dart
void main() {
  // var — 类型自动推断
  var name = '张三';           // 推断为 String
  var age = 25;                // 推断为 int
  var isStudent = true;        // 推断为 bool

  // 显式类型声明
  String city = '深圳';
  int score = 100;
  double price = 99.9;
  bool isActive = true;

  // final — 运行时常量(只能赋值一次)
  final DateTime now = DateTime.now();  // 运行时确定
  final username = 'flutter_dev';       // 一旦赋值不可修改

  // const — 编译时常量(必须是编译期可确定的值)
  const double pi = 3.14159;
  const String appName = 'My Flutter App';

  print('$name, $age 岁, 来自 $city');
  // 输出:张三, 25 岁, 来自 深圳
}

var vs final vs const

关键字可否重新赋值何时确定值使用场景
var✅ 可以运行时会变化的变量
final❌ 不可以运行时运行时确定的不变值
const❌ 不可以编译时编译期就确定的常量
dart
void main() {
  var count = 0;
  count = 10;       // ✅ var 可以重新赋值

  final time = DateTime.now();
  // time = DateTime.now();  // ❌ 错误!final 不能重新赋值

  const pi = 3.14;
  // const now = DateTime.now();  // ❌ 错误!DateTime.now() 不是编译时常量
}

基本数据类型

dart
void main() {
  // 数字类型
  int count = 42;
  double price = 29.99;
  num anything = 100;    // num 是 int 和 double 的父类
  anything = 3.14;       // 可以赋值 double

  // 字符串
  String greeting = 'Hello, Flutter!';
  String multiLine = '''
    这是一个
    多行字符串
  ''';

  // 字符串插值
  String name = '小明';
  String message = '你好, $name!你今年 ${age + 1} 岁了。';

  // 布尔
  bool isReady = true;
  bool isEmpty = false;

  // 类型转换
  String numStr = '42';
  int parsed = int.parse(numStr);       // 字符串 → 整数
  double parsed2 = double.parse('3.14'); // 字符串 → 浮点数
  String back = 42.toString();          // 数字 → 字符串
  String fixed = 3.14159.toStringAsFixed(2);  // '3.14'

  print('价格: ¥${price.toStringAsFixed(2)}');  // 价格: ¥29.99
}

空安全(Null Safety)

dart
void main() {
  // 默认情况下变量不能为 null
  String name = '张三';  // 不能赋值为 null
  // name = null;        // ❌ 编译错误

  // 用 ? 声明可空类型
  String? nickname;      // 默认值为 null
  nickname = '小张';
  nickname = null;       // ✅ 可空类型可以赋值 null

  // 空值判断
  print(nickname?.length);    // 安全访问:如果 null 返回 null
  print(nickname ?? '无昵称');  // 空值替代:如果 null 使用默认值
  
  // 非空断言(确定不为 null 时使用)
  String? input = getUserInput();
  if (input != null) {
    print(input.length);  // 编译器知道这里不为 null
  }

  // ! 强制非空(谨慎使用,可能抛出异常)
  // print(nickname!.length);  // 如果 nickname 为 null 会崩溃
}

🔧 2. 函数

基本函数

dart
// 有返回值的函数
int add(int a, int b) {
  return a + b;
}

// 无返回值
void greet(String name) {
  print('Hello, $name!');
}

// 箭头函数(一行表达式)
int multiply(int a, int b) => a * b;
void sayHi() => print('Hi!');

void main() {
  print(add(3, 5));       // 8
  greet('Flutter');        // Hello, Flutter!
  print(multiply(4, 6));  // 24
}

参数类型

dart
// ① 必需参数
int add(int a, int b) => a + b;

// ② 可选命名参数(用 {} 包裹)— Flutter 中最常用!
void createUser({
  required String name,   // required 标记为必填
  int age = 0,            // 默认值
  String? email,          // 可选
}) {
  print('姓名: $name, 年龄: $age, 邮箱: ${email ?? "未填写"}');
}

// ③ 可选位置参数(用 [] 包裹)
String greet(String name, [String? title]) {
  if (title != null) {
    return '$title $name, 您好!';
  }
  return '$name, 您好!';
}

void main() {
  createUser(name: '张三');                    // 姓名: 张三, 年龄: 0
  createUser(name: '李四', age: 25, email: 'li@test.com');
  
  print(greet('王五'));             // 王五, 您好!
  print(greet('王五', '教授'));      // 教授 王五, 您好!
}

高阶函数与闭包

dart
void main() {
  // 函数作为参数
  List<int> numbers = [1, 2, 3, 4, 5];

  // map — 转换每个元素
  var doubled = numbers.map((n) => n * 2).toList();
  print(doubled);  // [2, 4, 6, 8, 10]

  // where — 过滤
  var evens = numbers.where((n) => n % 2 == 0).toList();
  print(evens);  // [2, 4]

  // reduce — 聚合
  var sum = numbers.reduce((a, b) => a + b);
  print(sum);  // 15

  // forEach — 遍历
  numbers.forEach((n) => print('数字: $n'));

  // 闭包
  Function makeCounter() {
    int count = 0;
    return () {
      count++;
      return count;
    };
  }

  var counter = makeCounter();
  print(counter());  // 1
  print(counter());  // 2
  print(counter());  // 3
}

🏛 3. 面向对象

类的基本定义

dart
class Person {
  // 属性
  String name;
  int age;
  String? email;  // 可选属性

  // 构造函数 — Dart 的简写方式
  Person({required this.name, required this.age, this.email});

  // 命名构造函数
  Person.guest() : name = '游客', age = 0;

  Person.fromJson(Map<String, dynamic> json)
      : name = json['name'] as String,
        age = json['age'] as int,
        email = json['email'] as String?;

  // 方法
  String introduce() {
    return '我是 $name,今年 $age 岁';
  }

  // Getter
  bool get isAdult => age >= 18;

  // toString
  @override
  String toString() => 'Person(name: $name, age: $age)';
}

void main() {
  var person = Person(name: '张三', age: 25);
  print(person.introduce());  // 我是 张三,今年 25 岁
  print(person.isAdult);      // true

  var guest = Person.guest();
  print(guest);  // Person(name: 游客, age: 0)

  var fromData = Person.fromJson({'name': '李四', 'age': 30, 'email': null});
  print(fromData.introduce());  // 我是 李四,今年 30 岁
}

继承

dart
// 基类
class Animal {
  String name;
  Animal(this.name);

  void speak() {
    print('$name 发出声音');
  }
}

// 子类
class Dog extends Animal {
  String breed;

  Dog({required String name, required this.breed}) : super(name);

  @override
  void speak() {
    print('$name ($breed): 汪汪汪!');
  }

  void fetch() {
    print('$name 去捡球了');
  }
}

class Cat extends Animal {
  Cat(String name) : super(name);

  @override
  void speak() {
    print('$name: 喵~');
  }
}

void main() {
  var dog = Dog(name: '旺财', breed: '金毛');
  dog.speak();   // 旺财 (金毛): 汪汪汪!
  dog.fetch();   // 旺财 去捡球了

  var cat = Cat('咪咪');
  cat.speak();   // 咪咪: 喵~

  // 多态
  List<Animal> animals = [dog, cat];
  for (var animal in animals) {
    animal.speak();  // 各自调用自己的 speak
  }
}

抽象类与接口

dart
// 抽象类 — 定义契约
abstract class Shape {
  double get area;         // 抽象 getter
  double get perimeter;    // 抽象 getter
  String describe();       // 抽象方法
}

// 实现抽象类
class Circle extends Shape {
  final double radius;
  Circle(this.radius);

  @override
  double get area => 3.14159 * radius * radius;

  @override
  double get perimeter => 2 * 3.14159 * radius;

  @override
  String describe() => '圆形: 半径=$radius, 面积=${area.toStringAsFixed(2)}';
}

class Rectangle extends Shape {
  final double width;
  final double height;
  Rectangle(this.width, this.height);

  @override
  double get area => width * height;

  @override
  double get perimeter => 2 * (width + height);

  @override
  String describe() => '矩形: ${width}x$height, 面积=$area';
}

void main() {
  List<Shape> shapes = [Circle(5), Rectangle(4, 6)];
  for (var shape in shapes) {
    print(shape.describe());
  }
  // 圆形: 半径=5.0, 面积=78.54
  // 矩形: 4.0x6.0, 面积=24.0
}

Mixin(混入)

dart
// Mixin — 复用代码而不用继承
mixin Loggable {
  void log(String message) {
    print('[${DateTime.now()}] $message');
  }
}

mixin Validatable {
  bool validate(String value) {
    return value.isNotEmpty;
  }
}

// 一个类可以混入多个 Mixin
class UserService with Loggable, Validatable {
  void createUser(String name) {
    if (!validate(name)) {
      log('错误:用户名不能为空');
      return;
    }
    log('创建用户: $name');
  }
}

void main() {
  var service = UserService();
  service.createUser('');      // [时间] 错误:用户名不能为空
  service.createUser('张三');  // [时间] 创建用户: 张三
}

📦 4. 集合

List(列表)

dart
void main() {
  // 创建列表
  var fruits = ['苹果', '香蕉', '橙子'];
  List<int> numbers = [1, 2, 3, 4, 5];
  var empty = <String>[];  // 空列表

  // 添加元素
  fruits.add('葡萄');
  fruits.addAll(['西瓜', '草莓']);
  fruits.insert(0, '芒果');  // 在索引 0 插入

  // 访问元素
  print(fruits[0]);         // 芒果
  print(fruits.first);      // 芒果
  print(fruits.last);       // 草莓
  print(fruits.length);     // 7

  // 删除元素
  fruits.remove('香蕉');
  fruits.removeAt(0);
  fruits.removeLast();

  // 查找
  print(fruits.contains('苹果'));  // true
  print(fruits.indexOf('橙子'));   // 索引位置

  // 遍历与转换
  var prices = [10, 20, 30, 40];
  var discounted = prices.map((p) => p * 0.8).toList();
  var expensive = prices.where((p) => p > 20).toList();
  var total = prices.reduce((a, b) => a + b);

  print(discounted);  // [8.0, 16.0, 24.0, 32.0]
  print(expensive);   // [30, 40]
  print(total);       // 100

  // 展开运算符
  var list1 = [1, 2, 3];
  var list2 = [0, ...list1, 4, 5];
  print(list2);  // [0, 1, 2, 3, 4, 5]

  // 集合 if / for
  var nav = [
    '首页',
    '分类',
    if (isLoggedIn) '我的',
    for (var page in extraPages) page,
  ];
}

Map(映射)

dart
void main() {
  // 创建 Map
  var user = {
    'name': '张三',
    'age': 25,
    'city': '深圳',
  };

  Map<String, int> scores = {
    '语文': 90,
    '数学': 95,
    '英语': 88,
  };

  // 访问
  print(user['name']);       // 张三
  print(scores['数学']);     // 95

  // 添加 / 修改
  user['email'] = 'zhangsan@example.com';
  scores['物理'] = 92;

  // 删除
  user.remove('city');

  // 遍历
  scores.forEach((subject, score) {
    print('$subject: $score 分');
  });

  // 转换
  var entries = scores.entries.toList();
  var keys = scores.keys.toList();
  var values = scores.values.toList();

  // 检查
  print(scores.containsKey('数学'));  // true
  print(scores.isEmpty);             // false
}

Set(集合)

dart
void main() {
  // Set — 不重复的集合
  var tags = {'Flutter', 'Dart', 'Mobile'};
  tags.add('Flutter');  // 不会重复添加
  print(tags);  // {Flutter, Dart, Mobile}

  // 去重
  var list = [1, 2, 2, 3, 3, 3];
  var unique = list.toSet().toList();
  print(unique);  // [1, 2, 3]

  // 集合运算
  var a = {1, 2, 3, 4};
  var b = {3, 4, 5, 6};
  print(a.intersection(b));  // {3, 4}(交集)
  print(a.union(b));         // {1, 2, 3, 4, 5, 6}(并集)
  print(a.difference(b));    // {1, 2}(差集)
}

⏳ 5. 异步编程

Future(单次异步)

dart
// 模拟网络请求
Future<String> fetchUserName() async {
  // 模拟 2 秒延迟
  await Future.delayed(const Duration(seconds: 2));
  return '张三';
}

Future<int> fetchUserAge() async {
  await Future.delayed(const Duration(seconds: 1));
  return 25;
}

void main() async {
  print('开始获取数据...');

  // 顺序执行
  var name = await fetchUserName();
  var age = await fetchUserAge();
  print('$name, $age 岁');  // 总共 3 秒

  // 并行执行(节省时间!)
  var results = await Future.wait([
    fetchUserName(),
    fetchUserAge(),
  ]);
  print('${results[0]}, ${results[1]} 岁');  // 只需 2 秒
}

错误处理

dart
Future<String> fetchData() async {
  await Future.delayed(const Duration(seconds: 1));
  throw Exception('网络连接失败');
}

void main() async {
  // try-catch 处理异步错误
  try {
    var data = await fetchData();
    print(data);
  } on FormatException catch (e) {
    print('格式错误: $e');
  } on Exception catch (e) {
    print('请求异常: $e');
  } catch (e) {
    print('未知错误: $e');
  } finally {
    print('请求结束');
  }

  // 使用 .then / .catchError(链式写法)
  fetchData()
      .then((data) => print(data))
      .catchError((e) => print('错误: $e'));
}

Stream(持续数据流)

dart
// 创建 Stream
Stream<int> countDown(int from) async* {
  for (var i = from; i >= 0; i--) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;  // 逐个发送数据
  }
}

void main() async {
  // 监听 Stream
  print('倒计时开始:');
  await for (var value in countDown(5)) {
    print(value);  // 5, 4, 3, 2, 1, 0(每秒输出一个)
  }
  print('倒计时结束!');

  // Stream 转换
  var numbers = Stream.fromIterable([1, 2, 3, 4, 5]);
  var evens = numbers.where((n) => n % 2 == 0);
  await evens.forEach((n) => print('偶数: $n'));  // 偶数: 2, 偶数: 4
}

🧩 6. Dart 独有特性

枚举增强

dart
enum Status {
  idle('空闲', '⚪'),
  loading('加载中', '🔵'),
  success('成功', '🟢'),
  error('失败', '🔴');

  final String label;
  final String icon;
  const Status(this.label, this.icon);

  @override
  String toString() => '$icon $label';
}

void main() {
  var status = Status.loading;
  print(status);         // 🔵 加载中
  print(status.label);   // 加载中

  // switch 表达式
  var message = switch (status) {
    Status.idle => '等待操作',
    Status.loading => '请稍候...',
    Status.success => '操作完成!',
    Status.error => '出错了!',
  };
  print(message);
}

扩展方法

dart
// 给 String 类型添加新方法
extension StringExtension on String {
  // 首字母大写
  String get capitalize =>
      isEmpty ? '' : '${this[0].toUpperCase()}${substring(1)}';

  // 是否是有效邮箱
  bool get isValidEmail =>
      RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this);

  // 脱敏处理
  String get masked {
    if (length <= 3) return '***';
    return '${substring(0, 1)}${'*' * (length - 2)}${substring(length - 1)}';
  }
}

// 给 int 添加方法
extension IntExtension on int {
  // 格式化为货币
  String get currency =>${toStringAsFixed(2)}';

  // 是否是偶数(比 isEven 更语义化的用法)
  Duration get seconds => Duration(seconds: this);
  Duration get milliseconds => Duration(milliseconds: this);
}

void main() {
  print('hello'.capitalize);           // Hello
  print('test@email.com'.isValidEmail); // true
  print('张三丰'.masked);              // 张*丰

  // 使用扩展的 Duration
  await Future.delayed(2.seconds);
}

模式匹配(Dart 3)

dart
// sealed class + 模式匹配
sealed class Result<T> {}
class Success<T> extends Result<T> {
  final T data;
  Success(this.data);
}
class Failure<T> extends Result<T> {
  final String message;
  Failure(this.message);
}
class Loading<T> extends Result<T> {}

void handleResult(Result<String> result) {
  // switch 表达式 — 编译器确保覆盖所有情况
  var output = switch (result) {
    Success(data: var d) => '数据: $d',
    Failure(message: var m) => '错误: $m',
    Loading() => '加载中...',
  };
  print(output);
}

// 解构赋值
void main() {
  var (name, age) = ('张三', 25);
  print('$name, $age');

  var {'x': x, 'y': y} = {'x': 10, 'y': 20};
  print('坐标: ($x, $y)');

  // if-case 模式匹配
  var json = {'name': '张三', 'age': 25};
  if (json case {'name': String name, 'age': int age}) {
    print('$name, $age 岁');
  }
}

✅ 本篇小结 Checklist


下一篇预告:《Flutter 初体验:第一个 App 的诞生》—— 搭建开发环境, 创建并运行你的第一个 Flutter 应用,理解 Widget 的核心概念。


本文是「Flutter 从零到一」系列第 1 篇,共 13 篇。查看完整目录


📝 作者:NIHoa | 系列:Flutter从零到一系列 | 更新日期:2025-03-01