Dart 常被拿来和 Flutter 一起学习,但很多初学者卡住的并不是框架,而是语言本身:变量怎么声明、空安全怎么处理、函数和类该怎么写、异步代码到底怎么读。下面这篇入门整理按“环境搭建 → 基础语法 → 常用能力 → 综合练习”的顺序展开,保留原始示例代码和关键命令,帮助你先把 Dart 跑起来,再对常见写法建立一套清晰判断。
环境搭建与第一个 Dart 程序
如何安装 Dart SDK
开始之前,先把 Dart 开发环境装好。原始安装入口仍然是官方页面:

- 官网下载:dart.dev/get-dart
- 验证安装:
dart --version
能正确输出版本信息,就说明命令行环境已经可用,后续示例可以直接运行。
第一个程序怎么写
Dart 程序的入口是 main()。先从最简单的输出开始:
void main() {
print('Hello, Dart World!');
}
运行结果:
Hello, Dart World!
如果这段代码可以正常输出,说明你的 SDK、命令行和基础执行链路都没有问题,后面就可以进入语法学习。
变量、数据类型与常用运算
变量声明有哪些常见方式
Dart 支持类型推断、显式声明、动态类型以及常量声明。刚入门时,先分清 var、显式类型、dynamic、final 和 const 的使用场景,比死记语法更重要。

var name = 'Alice'; // 类型推断
String city = 'London'; // 显式声明
dynamic anything = 5; // 动态类型
final PI = 3.14; // 运行时常量
const gra vity = 9.8; // 编译时常量
这里可以直接记住两点:一是一般变量优先用明确或可推断的类型;二是不需要修改的值优先考虑 final,如果值在编译期就能确定,再使用 const。
Dart 的基本数据类型够不够用
对多数入门练习来说,Dart 的整数、浮点数、布尔值、字符串、列表和映射已经覆盖了主要需求:
int age = 25; // 整数
double price = 9.99; // 浮点数
bool isStudent = true; // 布尔值
String greeting = 'Hello'; // 字符串
List numbers = [1,2,3]; // 列表
Map scores = { // Map集合
'Math': 90,
'English': 85
};
其中 List 和 Map 也顺带体现了 Dart 的泛型写法,这对后面理解集合和自定义类会有帮助。
类型检查与转换怎么处理
开发中经常会碰到“字符串转数字”“数字再转回字符串”的情况。Dart 对此提供了直接可读的写法:
var value = '123';
print(value is String); // true
int numValue = int.parse(value);
String strValue = numValue.toString();
is 用于类型判断,int.parse() 和 toString() 则是最常见的双向转换方式。入门阶段把这三种写法用熟,已经能解决不少基础数据处理问题。
基础运算符和空安全运算符怎么理解
Dart 的算术运算与常见语言差别不大,但空安全相关运算符是必须尽早掌握的部分。
int a = 10, b = 3;
print(a + b); // 13
print(a ~/ b); // 3 (整除)
print(a++); // 10 (后置递增)
String nullableName;
print(nullableName 'Default'); // 空合并
print(nullableName.length); // 安全访问
~/ 表示整除,适合需要整数结果的场景。空安全部分里, 用来提供默认值,. 用来避免空对象访问报错,这两者在实际项目里的出场率非常高。
控制流程与函数写法
条件判断与三元表达式
当你需要根据不同条件输出不同结果时,Dart 的 if / else if / else 结构足够直接;条件简单时,也可以改用三元表达式压缩代码。
int score = 85;
if (score >= 90) {
print('优秀');
} else if (score >= 60) {
print('及格');
} else {
print('不及格');
}
// 三元运算符
var result = score >= 60 '通过' : '补考';
这类代码不复杂,但很适合拿来熟悉 Dart 的块级结构和表达式风格。
for、for-in 和 while 分别适合什么场景
循环语句主要看你是“按次数遍历”,还是“按集合内容遍历”。
// for循环
for (var i = 0; i < 5; i++) {
print(i);
}
// for-in循环
var fruits = ['apple', 'banana', 'orange'];
for (var fruit in fruits) {
print(fruit);
}
// while循环
int count = 3;
while (count > 0) {
print(count--);
}
for 更适合明确下标和次数,for-in 适合直接遍历集合元素,while 则适合依赖条件持续执行的场景。
函数定义、箭头函数与参数类型
函数是 Dart 代码复用的基础。先看普通函数和箭头函数:
// 函数定义
double calculateBMI(double weight, double height) {
return weight / (height * height);
}
// 箭头函数
String greet(String name) => 'Hello, $name!';
void main() {
print(calculateBMI(70, 1.75)); // 22.857
print(greet('Bob')); // Hello, Bob!
}
如果函数逻辑只有一行返回值,箭头函数会更简洁。接着看命名参数和可选参数:
// 命名参数
void register({String name, int age}) {
print('$name ($age) registered');
}
// 可选参数
String say(String from, [String to]) {
return to != null '$from to $to' : from;
}
void main() {
register(name: 'Alice', age: 25);
print(say('Hello')); // Hello
print(say('Hi', 'there')); // Hi to there
}
命名参数更适合字段较多、强调可读性的调用方式;可选参数则适合参数不一定总会传入的简单场景。
面向对象、集合与异常处理
类、对象与构造函数怎么入门
Dart 的面向对象写法比较直观,适合从“属性 + 构造函数 + 方法”这一最小组合开始理解。
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
// 命名构造函数
Person.newborn(String name) : this(name, 0);
// 方法
void introduce() {
print('我是$name,今年$age岁');
}
}
void main() {
var p1 = Person('Alice', 25);
var baby = Person.newborn('Charlie');
p1.introduce(); // 我是Alice,今年25岁
}
这个例子里已经包含了 Dart 类最常见的几部分:字段、普通构造函数、命名构造函数和实例方法。理解这一层后,再继续看继承和多态会更顺。
继承、多态和 Mixin 有什么区别
继承用于扩展父类能力,多态体现为“父类类型引用子类对象”,Mixin 则更像是把一组能力组合进类中。
class Animal {
void makeSound() => print('---');
}
class Dog extends Animal {
@override
void makeSound() => print('汪汪!');
}
void main() {
Animal myPet = Dog();
myPet.makeSound(); // 汪汪!
}
mixin Flyable {
void fly() => print('飞行中...');
}
class Bird with Flyable {}
void main() {
var sparrow = Bird();
sparrow.fly(); // 飞行中...
}
入门时可以这样记:extends 是“是一种”,with 是“具备某种能力”。
集合操作和泛型该先掌握哪些
集合是日常开发的高频内容,而泛型决定了集合和类中数据的类型约束。
var numbers = [1, 2, 3];
numbers.add(4);
numbers.removeAt(0);
print(numbers.where((n) => n > 2)); // (3,4)
var capitals = {
'China': 'Beijing',
'Japan': 'Tokyo'
};
capitals['USA'] = 'Washington';
print(capitals.containsKey('China')); // true
class Box {
T content;
Box(this.content);
}
void main() {
var stringBox = Box('Secret');
var intBox = Box(42);
}
List 和 Map 的增删查改是基础操作,而泛型 的意义在于让代码既能复用,又不丢失类型信息。
异常处理怎么写得更稳妥
当代码可能抛出错误时,Dart 提供了 try、on、catch 和 finally 这套完整结构。
void main() {
try {
var result = 100 ~/ 0;
} on IntegerDivisionByZeroException {
print('除数不能为零!');
} catch (e) {
print('未知错误: $e');
} finally {
print('处理完成');
}
}
这里展示的是一个典型场景:先精确捕获已知异常,再用 catch 兜底,最后通过 finally 收尾。
异步编程、综合案例与最佳实践
Future 和 async/await 怎么配合
Dart 在异步编程上的核心是 Future。当一个操作需要等待,例如网络请求、文件读取或定时任务,就会用到它。
Future fetchUser() async {
await Future.delayed(Duration(seconds: 1));
return '用户数据';
}
void main() async {
print('开始获取...');
var user = await fetchUser();
print('获取到:$user');
}
这段代码展示了最基础的异步流程:先声明异步函数,再在调用端使用 await 等待结果返回。
Stream 适合处理什么数据流
如果不是一次性拿到结果,而是持续按时间或事件产出数据,就更适合使用 Stream。
Stream countStream(int to) async* {
for (int i = 1; i <= to; i++) {
await Future.delayed(Duration(milliseconds: 500));
yield i;
}
}
void main() async {
await for (var num in countStream(3)) {
print(num); // 间隔0.5秒输出1,2,3
}
}
和 Future 相比,Stream 更像一个连续输出结果的管道,适合消息、计数、事件监听等场景。
综合案例:温度转换器
把前面的类、构造函数、getter 和工厂构造方法组合起来,就可以写出一个小型实用示例:
class Temperature {
double celsius;
Temperature(this.celsius);
double get fahrenheit => celsius * 9/5 + 32;
factory Temperature.fromFahrenheit(double f) {
return Temperature((f - 32) * 5/9);
}
}
void main() {
var t1 = Temperature(25);
print('25°C = ${t1.fahrenheit.toStringAsFixed(1)}°F'); // 77.0°F
var t2 = Temperature.fromFahrenheit(77);
print('77°F = ${t2.celsius}°C'); // 25°C
}
这个例子有两个值得注意的点:一是用 getter 提供华氏度计算结果,二是通过 factory 构造函数支持从另一种单位创建对象。
最佳实践与后续练习
如果你已经能读懂前面的代码,接下来就该开始整理开发习惯。原文给出的建议可以直接作为入门阶段的基本规范:
- 始终启用空安全
- 使用final声明不需要修改的变量
- 优先使用运算符处理空值
- 对于简单构造函数使用语法糖形式
- 异步操作统一使用async/await
- 集合操作多使用高阶函数(map, where, reduce等)
再往下一步,可以通过一个小练习把类、集合和方法串起来。原始示例是一个简易待办事项应用,虽然介绍里误写成了“深入了解HTML的应用与实践”,但实际代码仍然是 Dart:
- 使用类管理待办事项
- 支持添加/删除任务
- 可以标记任务完成状态
- 保存数据到本地文件
class TodoItem {
String title;
bool isDone;
TodoItem(this.title, [this.isDone = false]);
}
class TodoList {
final List _items = [];
void add(String title) => _items.add(TodoItem(title));
void remove(int index) => _items.removeAt(index);
void toggleDone(int index) {
_items[index].isDone = !_items[index].isDone;
}
void display() {
_items.asMap().forEach((i, item) {
print('${i+1}. [${item.isDone '' : ' '}] ${item.title}');
});
}
}
void main() {
var myList = TodoList();
myList.add('学习Dart');
myList.add('练习Flutter');
myList.toggleDone(0);
myList.display();
}
输出结果:
1. [] 学习Dart
2. [ ] 练习Flutter
这个练习很适合作为 Dart 入门后的第一道综合题。它覆盖了类设计、列表管理、状态切换和输出展示,也能自然过渡到文件存储、命令行交互,或者后续的 Flutter UI 开发。







