Dart 语言基础
Dart 是什么
Dart 是由 Google 开发的一种客户端优化的编程语言,专为快速构建高质量应用而设计。它是 Flutter 的官方开发语言。
Dart is an approachable, portable, and productive programming language for building high-quality apps on any platform.
— dart.dev
为什么选择 Dart
| 特性 | 说明 |
|---|---|
| 类型安全 | 支持空安全 (Null Safety),编译时捕获空指针错误 |
| 高性能 | AOT 编译为原生代码,JIT 支持热重载开发 |
| 跨平台 | 编译到 ARM、x64、JavaScript、WebAssembly |
| 现代语法 | async/await、Records、Patterns、模式匹配 |
| Flutter 专属 | 与 Flutter 深度集成,UI 即代码 |
知识结构
Hello World
Dart 程序的入口是 main 函数。
void main() { print('Hello, Dart!');}变量和常量
变量声明
// 使用 var 自动推断类型var name = 'Dart';var age = 10;
// 显式声明类型String language = 'Dart';int version = 3;double pi = 3.14159;bool isAwesome = true;var、final、const 对比
| 特性 | var | final | const |
|---|---|---|---|
| 可重新赋值 | 可以 | 不可以 | 不可以 |
| 初始化时机 | 运行时 | 运行时 | 编译时 |
| 类型推断 | 支持 | 支持 | 支持 |
| 值的可变性 | 值可变 | 引用不可变,值可能可变 | 深度不可变 |
// var: 可重新赋值的变量var name = 'Dart';name = 'Flutter'; // OK - 可以重新赋值
// final: 只能赋值一次,运行时确定final now = DateTime.now(); // OK - 可以使用运行时值// now = DateTime.now(); // Error - 不能重新赋值
// const: 编译时常量,值必须在编译时确定const pi = 3.14159;const maxItems = 100;// const time = DateTime.now(); // Error - DateTime.now() 是运行时值集合的可变性差异
// var 集合:引用和内容都可变var list1 = [1, 2, 3];list1.add(4); // OK - 可以修改内容list1 = [5, 6, 7]; // OK - 可以重新赋值
// final 集合:引用不可变,但内容可变final list2 = [1, 2, 3];list2.add(4); // OK - 可以修改内容// list2 = [5, 6, 7]; // Error - 不能重新赋值
// const 集合:引用和内容都不可变const list3 = [1, 2, 3];// list3.add(4); // Error - 不能修改内容// list3 = [5, 6, 7]; // Error - 不能重新赋值
// final + const:引用不可变,内容也不可变final list4 = const [1, 2, 3];// list4.add(4); // Error - 不能修改内容// list4 = [5, 6, 7]; // Error - 不能重新赋值使用建议
// 1. 优先使用 const(性能最好,编译时优化)const appName = 'MyApp';const defaultPadding = 16.0;
// 2. 需要运行时确定的不可变值用 finalfinal currentUser = await fetchUser();final screenWidth = MediaQuery.of(context).size.width;
// 3. 只有需要重新赋值时才用 varvar counter = 0;counter++; // 需要修改
// 4. 类成员变量class Config { static const version = '1.0.0'; // 编译时常量 final String userId; // 实例创建时确定 var isLoggedIn = false; // 需要修改的状态
Config(this.userId);}可空类型
Dart 2.12 引入了空安全(Null Safety),变量默认不能为 null。
// 普通变量不能为 nullString name = 'Dart';// name = null; // 编译错误
// 使用 ? 声明可空变量String? nullableName;nullableName = null; // 可以
// 空值检查print(nullableName?.length); // 安全访问print(nullableName ?? 'default'); // 空值合并print(nullableName!.length); // 断言非空(谨慎使用)内置类型
Number
// 整数int count = 42;int hex = 0xFF;
// 浮点数double price = 9.99;double exponent = 1.42e5;
// num 可以是 int 或 doublenum value = 100;value = 3.14;Boolean
bool isReady = true;bool isEmpty = false;
// 条件表达式var result = isEmpty ? 'Empty' : 'Not empty';String
// 字符串声明String single = 'Single quotes';String double = "Double quotes";String multiLine = ''' This is a multi-line string''';
// 字符串插值var name = 'Dart';print('Hello, $name!');print('Length: ${name.length}');
// 常用方法'hello'.toUpperCase(); // HELLO' trim '.trim(); // trim'hello'.contains('ell'); // true'hello'.replaceAll('l', 'L'); // heLLo'a,b,c'.split(','); // [a, b, c]List
// 声明列表var list = [1, 2, 3];List<String> names = ['Alice', 'Bob'];
// 常用操作list.add(4);list.addAll([5, 6]);list.remove(1);list.removeAt(0);print(list.length);print(list.first);print(list.last);print(list.isEmpty);
// 遍历for (var item in list) { print(item);}
// 函数式操作list.map((e) => e * 2);list.where((e) => e > 2);list.reduce((a, b) => a + b);Set
// 集合(元素唯一)var set = {1, 2, 3};Set<String> tags = {'dart', 'flutter'};
set.add(4);set.add(1); // 不会重复添加set.contains(2); // trueset.remove(1);Map
// 键值对var map = {'name': 'Dart', 'version': 3};Map<String, int> scores = {'math': 90, 'english': 85};
// 操作map['type'] = 'language';print(map['name']);map.remove('version');
// 遍历map.forEach((key, value) { print('$key: $value');});
for (var entry in map.entries) { print('${entry.key}: ${entry.value}');}Dynamic 与 Object
// dynamic: 关闭类型检查dynamic anything = 'Hello';anything = 123;anything = true;
// Object: 所有类的基类Object obj = 'Hello';obj = 123;// obj.length; // 编译错误,Object 没有 length 属性Enum
enum Status { pending, approved, rejected }
var status = Status.pending;
switch (status) { case Status.pending: print('Waiting...'); break; case Status.approved: print('Approved!'); break; case Status.rejected: print('Rejected.'); break;}
// Dart 2.17+ 增强枚举enum Color { red(0xFF0000), green(0x00FF00), blue(0x0000FF);
final int value; const Color(this.value);}Records (Dart 3.0+)
Records 是 Dart 3.0 引入的新类型,用于将多个值打包成一个不可变的聚合对象。这解决了函数只能返回单个值的限制。
Records are an anonymous, immutable, aggregate type.
// 创建记录 - 位置字段var point = (10, 20);print(point.$1); // 10 (通过 $1, $2... 访问位置字段)print(point.$2); // 20
// 创建记录 - 命名字段var person = (name: 'Alice', age: 25);print(person.name); // Aliceprint(person.age); // 25
// 混合使用位置和命名字段var mixed = ('first', 2, third: true);print(mixed.$1); // firstprint(mixed.$2); // 2print(mixed.third); // true函数返回多个值
Records 最常见的用途是让函数返回多个值:
// 返回多个值 - 位置字段(String, int) getUserInfo() { return ('Alice', 25);}
// 返回多个值 - 命名字段(更清晰)({String name, int age}) getUserInfoNamed() { return (name: 'Alice', age: 25);}
void main() { // 解构位置字段 var (name, age) = getUserInfo(); print('$name is $age years old');
// 解构命名字段 var (:name, :age) = getUserInfoNamed(); // 等同于 var (name: name, age: age) = getUserInfoNamed();}Records vs 类
| 特性 | Records | Class |
|---|---|---|
| 定义方式 | 匿名,无需定义 | 需要 class 定义 |
| 可变性 | 不可变 | 可变或不可变 |
| 相等性 | 按值比较(结构相等) | 默认按引用比较 |
| 适用场景 | 简单数据聚合、多返回值 | 复杂逻辑、需要方法 |
// Records 相等性:相同结构和值即相等var r1 = (name: 'Dart', version: 3);var r2 = (name: 'Dart', version: 3);print(r1 == r2); // true - 按值比较
// 类型别名简化复杂记录typedef Point = ({int x, int y});typedef UserInfo = ({String name, int age, String email});
Point origin = (x: 0, y: 0);运算符
算术运算符
int a = 10;int b = 3;
print(a + b); // 13print(a - b); // 7print(a * b); // 30print(a / b); // 3.333...print(a ~/ b); // 3 (整除)print(a % b); // 1 (取余)
a++; // 11b--; // 2比较与逻辑运算符
// 比较运算符print(5 == 5); // trueprint(5 != 3); // trueprint(5 > 3); // trueprint(5 >= 5); // trueprint(3 < 5); // trueprint(3 <= 3); // true
// 逻辑运算符print(true && false); // falseprint(true || false); // trueprint(!true); // false赋值运算符
var x = 10;x += 5; // x = x + 5x -= 3; // x = x - 3x *= 2; // x = x * 2x ~/= 4; // x = x ~/ 4
// 空值赋值String? name;name ??= 'default'; // 仅当 name 为 null 时赋值自定义类操作符
可以为自定义类重载操作符。
class Vector { final double x, y;
Vector(this.x, this.y);
// 重载 + 运算符 Vector operator +(Vector other) { return Vector(x + other.x, y + other.y); }
// 重载 * 运算符 Vector operator *(double scalar) { return Vector(x * scalar, y * scalar); }
// 重载 == 运算符 @override bool operator ==(Object other) { if (other is! Vector) return false; return x == other.x && y == other.y; }
@override int get hashCode => Object.hash(x, y);
@override String toString() => 'Vector($x, $y)';}
void main() { var v1 = Vector(1, 2); var v2 = Vector(3, 4);
print(v1 + v2); // Vector(4.0, 6.0) print(v1 * 2); // Vector(2.0, 4.0)}函数
基本函数
// 普通函数int add(int a, int b) { return a + b;}
// 箭头函数(单表达式)int multiply(int a, int b) => a * b;
// 无返回值void sayHello(String name) { print('Hello, $name!');}可选参数
// 位置可选参数void greet(String name, [String? title, String suffix = '!']) { print('Hello, ${title ?? ''} $name$suffix');}
greet('Alice');greet('Bob', 'Mr.');greet('Charlie', 'Dr.', '.');命名参数
// 命名参数(默认可选)void createUser({String? name, int age = 0, required String email}) { print('Name: $name, Age: $age, Email: $email');}
createUser(email: 'test@example.com');createUser(name: 'Alice', age: 25, email: 'alice@example.com');匿名函数与闭包
// 匿名函数var list = [1, 2, 3];list.forEach((item) { print(item);});
// 闭包Function makeAdder(int addBy) { return (int i) => i + addBy;}
var add2 = makeAdder(2);print(add2(3)); // 5高阶函数
// 函数作为参数void repeat(int times, void Function(int) action) { for (var i = 0; i < times; i++) { action(i); }}
repeat(3, (i) => print('第 $i 次'));
// 函数作为返回值Function multiplyBy(int factor) { return (int value) => value * factor;}
var triple = multiplyBy(3);print(triple(4)); // 12级联操作符
使用 .. 可以对同一对象进行连续操作。
class Person { String name = ''; int age = 0;
void introduce() { print('I am $name, $age years old.'); }}
void main() { var person = Person() ..name = 'Alice' ..age = 25 ..introduce();
// 等同于 // var person = Person(); // person.name = 'Alice'; // person.age = 25; // person.introduce();}控制流
if-else
var score = 85;
if (score >= 90) { print('优秀');} else if (score >= 60) { print('及格');} else { print('不及格');}
// 三元运算符var result = score >= 60 ? '及格' : '不及格';switch
var command = 'start';
switch (command) { case 'start': print('Starting...'); break; case 'stop': print('Stopping...'); break; case 'restart': print('Restarting...'); break; default: print('Unknown command');}
// Dart 3.0 switch 表达式var message = switch (command) { 'start' => 'Starting...', 'stop' => 'Stopping...', _ => 'Unknown'};模式匹配 (Dart 3.0+)
Dart 3.0 引入了强大的模式匹配 (Pattern Matching) 功能,可以在 switch、if-case、变量声明等场景中使用。
Patterns are a syntactic category that let you match and destructure values.
if-case 模式匹配
var data = {'name': 'Alice', 'age': 25};
// if-case 解构 Mapif (data case {'name': String name, 'age': int age}) { print('$name is $age years old');}
// 匹配列表var list = [1, 2, 3];if (list case [var first, var second, ...]) { print('First: $first, Second: $second');}
// 匹配对象var point = Point(10, 20);if (point case Point(x: var x, y: var y) when x > 0) { print('Point in positive x: ($x, $y)');}switch 模式匹配
// 解构 Records(int, String) getData() => (200, 'OK');
void handleResponse() { var response = getData();
switch (response) { case (200, var message): print('Success: $message'); case (404, _): print('Not found'); case (var code, var message) when code >= 500: print('Server error $code: $message'); case (var code, _): print('Other status: $code'); }}
// 解构对象class Point { final int x, y; Point(this.x, this.y);}
String describePoint(Point p) => switch (p) { Point(x: 0, y: 0) => 'Origin', Point(x: 0, y: var y) => 'On Y axis at $y', Point(x: var x, y: 0) => 'On X axis at $x', Point(x: var x, y: var y) when x == y => 'On diagonal at $x', Point(x: var x, y: var y) => 'Point at ($x, $y)',};常用模式类型
| 模式类型 | 示例 | 说明 |
|---|---|---|
| 常量模式 | case 42: | 匹配特定值 |
| 变量模式 | case var x: | 绑定值到变量 |
| 通配符 | case _: | 匹配任意值,不绑定 |
| 记录模式 | case (a, b): | 解构 Records |
| 对象模式 | case Point(x: 0): | 解构对象属性 |
| 列表模式 | case [a, b, ...]: | 解构列表 |
| Map 模式 | case {'key': value}: | 解构 Map |
| 逻辑或 | case 1 | 2 | 3: | 匹配多个值 |
| 守卫条件 | case x when x > 0: | 添加额外条件 |
变量声明解构
// 解构列表var [a, b, ...rest] = [1, 2, 3, 4, 5];print('$a, $b, $rest'); // 1, 2, [3, 4, 5]
// 解构 Mapvar {'name': name, 'age': age} = {'name': 'Bob', 'age': 30, 'city': 'NYC'};
// 解构 Recordvar (lat, lng) = getCoordinates();
// 交换变量(无需临时变量)var x = 1, y = 2;(x, y) = (y, x);print('$x, $y'); // 2, 1
// for 循环解构var points = [(1, 2), (3, 4), (5, 6)];for (var (x, y) in points) { print('Point: ($x, $y)');}循环
for 循环
// 标准 forfor (var i = 0; i < 5; i++) { print(i);}
// for-invar list = ['a', 'b', 'c'];for (var item in list) { print(item);}
// forEachlist.forEach((item) => print(item));while 与 do-while
// whilevar count = 0;while (count < 3) { print(count); count++;}
// do-whilevar i = 0;do { print(i); i++;} while (i < 3);break 与 continue
for (var i = 0; i < 10; i++) { if (i == 5) break; // 终止循环 if (i % 2 == 0) continue; // 跳过本次 print(i);}异常处理
void main() { try { var result = 10 ~/ 0; print(result); } on IntegerDivisionByZeroException { print('不能除以零'); } on FormatException catch (e) { print('格式错误: $e'); } catch (e, stackTrace) { print('未知错误: $e'); print('堆栈: $stackTrace'); } finally { print('清理资源'); }}
// 抛出异常void validateAge(int age) { if (age < 0) { throw ArgumentError('年龄不能为负数'); } if (age > 150) { throw RangeError('年龄超出范围'); }}
// 自定义异常class ValidationException implements Exception { final String message; ValidationException(this.message);
@override String toString() => 'ValidationException: $message';}泛型
泛型类
class Box<T> { T value;
Box(this.value);
T getValue() => value; void setValue(T newValue) => value = newValue;}
void main() { var intBox = Box<int>(42); var stringBox = Box<String>('Hello');
print(intBox.getValue()); // 42 print(stringBox.getValue()); // Hello}泛型函数
T first<T>(List<T> list) { return list.first;}
void main() { print(first<int>([1, 2, 3])); // 1 print(first(['a', 'b', 'c'])); // a (类型推断)}泛型约束
// 限制 T 必须是 num 的子类class NumberBox<T extends num> { T value;
NumberBox(this.value);
T add(T other) => (value + other) as T;}
var intBox = NumberBox<int>(10);var doubleBox = NumberBox<double>(3.14);// var stringBox = NumberBox<String>('x'); // 编译错误Future 与异步
Future 基础
Future<String> fetchData() { return Future.delayed( Duration(seconds: 2), () => 'Data loaded', );}
void main() { print('Start');
fetchData().then((data) { print(data); }).catchError((error) { print('Error: $error'); }).whenComplete(() { print('Done'); });
print('Waiting...');}// 输出: Start -> Waiting... -> (2秒后) Data loaded -> Doneasync/await
Future<String> fetchUser() async { await Future.delayed(Duration(seconds: 1)); return 'Alice';}
Future<String> fetchEmail(String user) async { await Future.delayed(Duration(seconds: 1)); return '$user@example.com';}
Future<void> main() async { print('Start');
try { var user = await fetchUser(); print('User: $user');
var email = await fetchEmail(user); print('Email: $email'); } catch (e) { print('Error: $e'); }
print('Done');}并行执行
Future<void> main() async { // 并行执行多个 Future var results = await Future.wait([ fetchUser(), fetchData(), ]);
print(results); // [user, data]}Stream 异步流
Stream 用于处理一系列异步事件,而 Future 只能处理单个异步结果。
// 使用 async* 创建 StreamStream<int> countTo(int n) async* { for (int i = 1; i <= n; i++) { await Future.delayed(Duration(milliseconds: 500)); yield i; // 逐个发出值 }}
// 使用 await for 消费 StreamFuture<void> main() async { print('Start counting:');
await for (var number in countTo(5)) { print(number); }
print('Done!');}// 输出: Start counting: -> 1 -> 2 -> 3 -> 4 -> 5 -> Done!Stream 操作
Stream<int> numbers = Stream.fromIterable([1, 2, 3, 4, 5]);
// 转换操作numbers .map((n) => n * 2) // [2, 4, 6, 8, 10] .where((n) => n > 4) // [6, 8, 10] .listen((n) => print(n)); // 监听每个值
// 聚合操作var sum = await numbers.reduce((a, b) => a + b);var list = await numbers.toList();var first = await numbers.first;Stream vs Future
| 特性 | Future | Stream |
|---|---|---|
| 返回值数量 | 单个值 | 多个值序列 |
| 完成时机 | 一次性完成 | 可持续发送 |
| 适用场景 | HTTP 请求、文件读取 | WebSocket、用户输入、定时器 |
| 创建方式 | async 函数 | async* 函数 + yield |
yield* 委托
Stream<int> rangeStream(int start, int end) async* { for (int i = start; i <= end; i++) { yield i; }}
Stream<int> combinedStream() async* { yield* rangeStream(1, 3); // 委托给另一个 Stream yield 100; yield* rangeStream(4, 6);}// 输出: 1, 2, 3, 100, 4, 5, 6类与对象
基本类
class Person { String name; int age;
// 构造函数简写 Person(this.name, this.age);
// 命名构造函数 Person.guest() : name = 'Guest', age = 0;
// 工厂构造函数 factory Person.fromJson(Map<String, dynamic> json) { return Person(json['name'], json['age']); }
// 方法 void introduce() { print('I am $name, $age years old.'); }
// Getter bool get isAdult => age >= 18;
// Setter set nickname(String value) { name = value; }}私有成员
class BankAccount { // 下划线开头为私有(库级别) double _balance = 0;
double get balance => _balance;
void deposit(double amount) { if (amount > 0) { _balance += amount; } }
void withdraw(double amount) { if (amount > 0 && amount <= _balance) { _balance -= amount; } }}抽象类
abstract class Shape { // 抽象方法(没有实现) double area(); double perimeter();
// 普通方法 void describe() { print('Area: ${area()}, Perimeter: ${perimeter()}'); }}
class Circle extends Shape { final double radius;
Circle(this.radius);
@override double area() => 3.14159 * radius * radius;
@override double perimeter() => 2 * 3.14159 * radius;}
class Rectangle extends Shape { final double width, height;
Rectangle(this.width, this.height);
@override double area() => width * height;
@override double perimeter() => 2 * (width + height);}类修饰符 (Dart 3.0+)
Dart 3.0 引入了多个新的类修饰符,用于更精细地控制类的继承和实现方式。
Class modifiers control how a class or mixin can be used, both from within its own library, and from outside the library where it’s defined.
修饰符对比
| 修饰符 | 可实例化 | 可继承 | 可实现 | 说明 |
|---|---|---|---|---|
| (无) | 可以 | 可以 | 可以 | 普通类 |
| abstract | 不可以 | 可以 | 可以 | 抽象类 |
| base | 可以 | 可以 | 不可以 | 强制继承实现 |
| interface | 可以 | 不可以 | 可以 | 强制接口实现 |
| final | 可以 | 不可以 | 不可以 | 禁止扩展 |
| sealed | 不可以 | 同库可以 | 同库可以 | 穷尽检查 |
sealed 密封类
sealed 是最常用的新修饰符,用于创建受限的类型层次结构,配合模式匹配实现穷尽性检查。
// 定义密封类(只能在同一文件中扩展)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> {}
// 使用 switch 表达式(编译器确保处理所有情况)String handleResult(Result<String> result) => switch (result) { Success(data: var data) => 'Got: $data', Failure(message: var msg) => 'Error: $msg', Loading() => 'Loading...', // 无需 default,编译器知道所有可能的子类型};
void main() { var result = Success('Hello'); print(handleResult(result)); // Got: Hello}sealed 类的特点
- 隐式抽象:sealed 类不能直接实例化
- 同库限制:子类必须定义在同一个库(文件)中
- 穷尽检查:switch 表达式可以省略 default 分支
- 类型安全:编译器确保处理所有可能的子类型
实际应用:状态管理
// 定义 UI 状态sealed class UiState {}
class InitialState extends UiState {}class LoadingState extends UiState {}class SuccessState extends UiState { final List<String> items; SuccessState(this.items);}class ErrorState extends UiState { final String error; ErrorState(this.error);}
// 根据状态渲染 UIWidget buildUI(UiState state) => switch (state) { InitialState() => Text('Welcome!'), LoadingState() => CircularProgressIndicator(), SuccessState(items: var items) => ListView(children: items.map(Text.new).toList()), ErrorState(error: var e) => Text('Error: $e'),};base 和 final 修饰符
// base: 强制使用 extends,不能用 implementsbase class Animal { void breathe() => print('Breathing...');}
class Dog extends Animal {} // OK// class Cat implements Animal {} // Error: 不能实现 base 类
// final: 禁止继承和实现final class Config { final String apiUrl; Config(this.apiUrl);}
// class MyConfig extends Config {} // Error: 不能继承 final 类接口
Dart 没有 interface 关键字,任何类都可以作为接口使用。Dart 3.0 引入了 interface 修饰符来明确表示接口意图。
// 定义接口(使用抽象类)abstract class Printable { void printContent();}
abstract class Savable { void save();}
// 实现多个接口class Document implements Printable, Savable { String content;
Document(this.content);
@override void printContent() { print(content); }
@override void save() { print('Saving document...'); }}继承
class Animal { String name;
Animal(this.name);
void speak() { print('$name makes a sound'); }}
class Dog extends Animal { String breed;
Dog(String name, this.breed) : super(name);
@override void speak() { print('$name barks'); }
void fetch() { print('$name fetches the ball'); }}
void main() { var dog = Dog('Buddy', 'Golden Retriever'); dog.speak(); // Buddy barks dog.fetch(); // Buddy fetches the ball}Mixin
Mixin 用于在多个类之间共享代码,不需要继承关系。
mixin Swimming { void swim() { print('Swimming...'); }}
mixin Flying { void fly() { print('Flying...'); }}
mixin Walking { void walk() { print('Walking...'); }}
class Duck with Swimming, Flying, Walking { String name;
Duck(this.name);}
class Fish with Swimming { String name;
Fish(this.name);}
void main() { var duck = Duck('Donald'); duck.swim(); duck.fly(); duck.walk();
var fish = Fish('Nemo'); fish.swim(); // fish.fly(); // 错误,Fish 没有 Flying mixin}库与导入
导入库
// 导入 Dart 核心库import 'dart:math';import 'dart:convert';import 'dart:async';
// 导入第三方包import 'package:http/http.dart';
// 导入本地文件import 'models/user.dart';import '../utils/helpers.dart';别名与部分导入
// 使用别名import 'package:lib1/lib1.dart' as lib1;import 'package:lib2/lib2.dart' as lib2;
lib1.Element element1 = lib1.Element();lib2.Element element2 = lib2.Element();
// 只导入部分import 'package:lib/lib.dart' show foo, bar;
// 隐藏部分import 'package:lib/lib.dart' hide baz;延迟加载
import 'package:heavy_lib/heavy.dart' deferred as heavy;
Future<void> loadHeavyLib() async { await heavy.loadLibrary(); heavy.doSomething();}扩展方法
extension StringExtension on String { String capitalize() { if (isEmpty) return this; return '${this[0].toUpperCase()}${substring(1)}'; }
bool get isEmail { return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(this); }}
void main() { print('hello'.capitalize()); // Hello print('test@example.com'.isEmail); // true}下一步
学习了 Dart 基础后,可以开始学习 Flutter:
- Flutter 基础笔记 - Widget、布局、状态管理等
- 官方文档:dart.dev
- Flutter 文档:flutter.dev