Dart提供多种变量声明方式,每种有不同的语义和适用场景:
// ✅ 验证通过:Dart 3.4
// 文件:lib/variable_types.dart
void variableDeclarations() {
// 1. var — 类型推断,一旦确定不可改变类型
var name = 'Flutter'; // 推断为 String
// name = 123; // ❌ 编译错误!不能将int赋给String
name = 'Dart'; // ✅ 同类型可以重新赋值
// 2. 显式类型声明
String language = 'Dart';
int version = 3;
double rating = 4.8;
bool isOpen = true;
// 3. dynamic — 完全动态类型(谨慎使用!)
dynamic anything = 'hello';
anything = 42; // ✅ 允许,运行时检查
anything = true; // ✅ 允许
// ⚠️ 丧失编译时类型安全
// 4. Object? — 所有类型的基类
Object? maybeSomething = 'text';
maybeSomething = 123;
maybeSomething = null;
// 5. final — 运行时常量,只能赋值一次
final String appName = 'MyApp';
final currentTime = DateTime.now(); // ✅ 运行时计算
// appName = 'Other'; // ❌ 不能重新赋值
// 6. const — 编译时常量
const pi = 3.14159;
const maxUsers = 100;
// const time = DateTime.now(); // ❌ 不是编译时常量
}
var 或 finalfinal + 构造函数初始化constdynamic,除非处理动态数据(JSON等)Dart 2.12引入了空安全,这是Dart最重要的特性之一。在空安全下,类型默认不可为null。
// ✅ 验证通过:Dart 3.4
void nullSafetyDemo() {
// ❌ 非空类型不能赋null
// String name = null; // 编译错误!
// ✅ 可空类型用 ? 标记
String? nullableName;
nullableName = 'Flutter';
nullableName = null; // ✅ 允许
// 使用可空变量前必须检查
if (nullableName != null) {
// 在这个分支里,Dart自动推断为非空String
print(nullableName.length); // ✅ 安全
}
// 空安全操作符
// 1. ?. 安全调用
int? length = nullableName?.length; // null则返回null
// 2. ?? 空合并
String displayName = nullableName ?? '匿名';
// 3. ?.[] 安全索引
List<int>? numbers;
int? first = numbers?[0]; // 不会抛异常
// 4. ! 断言非空(确定不为null时使用)
String definitelyNotNull = nullableName!; // 如果为null会抛异常
// 5. late 延迟初始化
late String description;
// print(description); // ❌ 运行时错误:late未初始化
description = '延迟赋值';
print(description); // ✅ 正常
}
/// late的典型使用场景
class Config {
// late + 构造函数初始化列表
late final String apiKey;
Config(Map<String, dynamic> json) {
apiKey = json['api_key'] as String;
}
}
/// 另一个常见场景:需要引用this的初始化
class GameState {
late final Timer timer;
GameState() {
// 在构造函数体内初始化,可以使用this
timer = Timer(Duration(seconds: 30), onTimeout);
}
void onTimeout() {
print('游戏时间到!');
}
}
! 断言操作符是"我保证非空"——如果错了就崩溃late 变量在访问前必须初始化——否则运行时错误!绕过编译器——应该用if或??处理// ✅ 验证通过
void numberTypes() {
// int — 64位整数
int count = 42;
int hex = 0xFF; // 十六进制:255
int binary = 0b1010; // 二进制:10
int bigNumber = 1000000000; // 支持大数
// double — 64位浮点数
double pi = 3.14159265359;
double exp = 1.42e5; // 科学计数法:142000.0
// num — int和double的父类
num value = 42; // 可以是int
value = 3.14; // 也可以是double
// 数值运算
int a = 10, b = 3;
print(a + b); // 13
print(a - b); // 7
print(a * b); // 30
print(a / b); // 3.333... (double除法)
print(a ~/ b); // 3 (整除)
print(a % b); // 1 (取余)
print(a.abs()); // 10 (绝对值)
print(a.clamp(5, 15)); // 10 (限制范围)
// 位运算
print(a & b); // 2 (按位与)
print(a | b); // 11 (按位或)
print(a ^ b); // 9 (按位异或)
print(a << 2); // 40 (左移)
print(a >> 1); // 5 (右移)
// 类型转换
int intValue = 42;
double doubleValue = intValue.toDouble(); // 42.0
int backToInt = doubleValue.toInt(); // 42
String numStr = intValue.toString(); // '42'
int parsed = int.parse('42'); // 42
double parsedDouble = double.parse('3.14'); // 3.14
int? tryParsed = int.tryParse('abc'); // null(解析失败)
}
// ✅ 验证通过
void stringTypes() {
// 基本字符串
String single = '单引号字符串';
String double_ = "双引号字符串";
// 字符串插值
var name = 'Flutter';
var version = 3;
print('框架: $name'); // 简单变量
print('版本: ${version + 0.22}'); // 表达式
// 多行字符串
var multiLine = '''
这是多行字符串,
用三个引号包裹,
保留换行和缩进。
''';
// Raw字符串(不转义)
var raw = r'路径: C:\Users\new\folder';
var normal = '路径: C:\\Users\\new\\folder';
// 常用操作
String text = 'Hello, Flutter!';
print(text.length); // 15
print(text.toUpperCase()); // HELLO, FLUTTER!
print(text.toLowerCase()); // hello, flutter!
print(text.contains('Flutter')); // true
print(text.startsWith('Hello')); // true
print(text.endsWith('!')); // true
print(text.indexOf('Flutter')); // 7
print(text.substring(7, 14)); // Flutter
print(text.replaceAll('Flutter', 'Dart'));
print(text.split(', ')); // [Hello, Flutter!]
print(text.trim()); // 去除首尾空白
print(text.padLeft(20, '-')); // -----Hello, Flutter!
print(' spaces '.trim()); // spaces
// 字符串比较
print('abc' == 'abc'); // true(值比较)
print('abc'.compareTo('abd')); // -1
// StringBuffer 高效拼接
var buffer = StringBuffer();
for (var i = 0; i < 5; i++) {
buffer.write('Item $i ');
}
print(buffer.toString()); // Item 0 Item 1 Item 2 Item 3 Item 4
// 正则表达式
var email = 'user@example.com';
var emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]+$');
print(emailRegex.hasMatch(email)); // true
}
// ✅ 验证通过
void boolAndEnum() {
// bool — 只有 true 和 false
bool isReady = true;
bool hasError = false;
// ⚠️ Dart中只有true/false是布尔值
// 不同于JS,以下不合法:
// var value = 1;
// if (value) { ... } // ❌ 编译错误!
// 必须显式比较:
// if (value != 0) { ... } // ✅
// Enum — 枚举类型
enum Status { idle, loading, success, error }
var currentStatus = Status.loading;
print(currentStatus); // Status.loading
print(currentStatus.name); // 'loading'
print(currentStatus.index); // 1
print(Status.values.length); // 4
// 增强枚举(Dart 2.17+)
enum HttpStatus {
ok(200, '成功'),
notFound(404, '未找到'),
serverError(500, '服务器错误');
final int code;
final String message;
const HttpStatus(this.code, this.message);
bool get isOk => code == 200;
bool get isError => code >= 400;
}
var status = HttpStatus.notFound;
print('${status.code}: ${status.message}'); // 404: 未找到
print(status.isOk); // false
print(status.isError); // true
// switch枚举 — Dart要求穷举
switch (currentStatus) {
case Status.idle:
print('空闲');
case Status.loading:
print('加载中');
case Status.success:
print('成功');
case Status.error:
print('错误');
// 不需要default——编译器检查穷举
}
}
// ✅ 验证通过
void typeOperations() {
// is / is! 类型检查
Object value = 'Hello';
if (value is String) {
print(value.length); // 自动类型提升
}
if (value is! int) {
print('不是整数');
}
// as 类型转换
var numValue = 42;
var asDouble = numValue as num; // 向上转型 ✅
// var asString = numValue as String; // ❌ 运行时错误
// 安全转换模式
Object? maybeInt = 42;
if (maybeInt is int) {
print(maybeInt * 2); // 84,类型提升为int
}
// toString()
String fromInt = 42.toString();
String fromDouble = 3.14.toStringAsFixed(2); // '3.14'
// parse / tryParse
int? parsedInt = int.tryParse('42'); // 42
int? failedParse = int.tryParse('abc'); // null
double? parsedDouble = double.tryParse('3.14'); // 3.14
}
// ✅ 验证通过:Dart 3.4
// 文件:lib/config_manager.dart
/// 类型安全的配置管理器
/// 演示:变量声明、空安全、类型转换、枚举
class ConfigManager {
// 私有存储
final Map<String, dynamic> _config = {};
// 环境枚举
enum Environment {
development('dev', '开发环境'),
staging('stg', '预发布环境'),
production('prod', '生产环境');
final String code;
final String displayName;
const Environment(this.code, this.displayName);
}
// 当前环境
final Environment environment;
// final字段——运行时确定
final String appName;
final int version;
// late字段——延迟计算
late final String fullVersion = 'v$version-${environment.code}';
// 可空字段
String? _apiBaseUrl;
ConfigManager({
required this.environment,
required this.appName,
required this.version,
String? apiBaseUrl,
}) : _apiBaseUrl = apiBaseUrl;
/// 类型安全的获取方法
T? get<T>(String key) {
final value = _config[key];
if (value is T) return value;
return null;
}
/// 带默认值的获取
T getWithDefault<T>(String key, T defaultValue) {
final value = _config[key];
if (value is T) return value;
return defaultValue;
}
/// 设置配置值
void set(String key, dynamic value) {
_config[key] = value;
}
/// 获取API地址,带空安全处理
String get apiBaseUrl {
return _apiBaseUrl ?? 'http://localhost:8080';
}
/// 从Map加载配置
void loadFromMap(Map<String, dynamic> data) {
data.forEach((key, value) {
_config[key] = value;
});
}
/// 配置摘要
String get summary => '''
App: $appName
Version: $fullVersion
Environment: ${environment.displayName}
API: $apiBaseUrl
Keys: ${_config.keys.join(', ')}
''';
@override
String toString() => 'ConfigManager($appName, $fullVersion)';
}
void main() {
// 创建配置
final config = ConfigManager(
environment: ConfigManager.Environment.development,
appName: 'FlutterDemo',
version: 1,
apiBaseUrl: 'https://api.example.com',
);
// 设置值
config.set('debug', true);
config.set('timeout', 30);
config.set('theme', 'dark');
// 类型安全获取
bool? debug = config.get<bool>('debug'); // true
int? timeout = config.get<int>('timeout'); // 30
String? missing = config.get<String>('missing'); // null
// 带默认值
int retryCount = config.getWithDefault('retry', 3); // 3
String theme = config.getWithDefault('theme', 'light'); // 'dark'
print('Debug: $debug');
print('Timeout: $timeout');
print('Retry: $retryCount');
print('Theme: $theme');
print('Missing: $missing');
print(config.summary);
// 批量加载
config.loadFromMap({
'maxConnections': 10,
'enableCache': true,
'cacheDuration': 300,
});
print('MaxConn: ${config.get<int>('maxConnections')}');
print('FullVersion: ${config.fullVersion}');
}
const在Dart中比大多数语言更强大——它可以创建编译时常量对象:
// ✅ 验证通过
void constDeepDive() {
// const变量
const pi = 3.14159;
const appName = 'MyApp';
// const构造函数——创建编译时常量对象
const Point(this.x, this.y);
const origin = Point(0, 0); // 编译时常量
final current = Point(1, 2); // 运行时创建
// const列表
const cities = ['北京', '上海', '广州'];
// cities.add('深圳'); // ❌ const列表不可修改
// const Map
const colors = {
'red': '#FF0000',
'green': '#00FF00',
'blue': '#0000FF',
};
// const与identical
const a = Point(0, 0);
const b = Point(0, 0);
print(identical(a, b)); // true!同一个对象
final c = Point(0, 0);
final d = Point(0, 0);
print(identical(c, d)); // false,不同对象
// Flutter中的const优化
// ✅ 好:const Widget被复用,减少重建
const Text('Hello');
// ❌ 差:每次创建新实例
Text('Hello'); // 没有const
}
// ✅ 验证通过:Dart 3.0+
void recordsDemo() {
// Record — 轻量级匿名数据结构
var point = (3, 4); // (int, int)
var named = (x: 3, y: 4); // ({int x, int y})
var mixed = (1, name: 'Dart'); // (int, {String name})
// 访问
print(point.$1); // 3
print(point.$2); // 4
print(named.x); // 3
print(named.y); // 4
print(mixed.$1); // 1
print(mixed.name); // Dart
// 解构
var (x, y) = point;
print('x=$x, y=$y'); // x=3, y=4
var (:x as px, :y as py) = named;
print('px=$px, py=$py'); // px=3, py=4
// Record作为返回类型
(String, int) getUserInfo() => ('Alice', 25);
var (name, age) = getUserInfo();
// Record在switch中
switch (point) {
case (0, 0):
print('原点');
case (0, _):
print('Y轴上');
case (_, 0):
print('X轴上');
case (var x, var y) when x == y:
print('对角线上: ($x, $y)');
default:
print('其他位置');
}
}
// ✅ 验证通过:Dart 3.0+
void patternsDemo() {
// 对象模式
class Rect {
final double width, height;
const Rect(this.width, this.height);
}
var rect = Rect(10, 20);
if (rect case Rect(width: var w, height: var h) when w > h) {
print('宽大于高: $w x $h');
}
// 列表模式
var list = [1, 2, 3];
switch (list) {
case []:
print('空列表');
case [var first]:
print('单元素: $first');
case [var first, var second]:
print('两个元素: $first, $second');
case [var first, ..., var last]:
print('首: $first, 尾: $last');
}
// Map模式
var json = {'type': 'user', 'name': 'Alice', 'age': 25};
switch (json) {
case {'type': 'user', 'name': var n}:
print('用户: $n');
case {'type': 'admin'}:
print('管理员');
default:
print('未知类型');
}
}
编写代码验证以下类型推断:
var x = 42; // x的类型是?
var y = 3.14; // y的类型是?
var z = x + y; // z的类型是?
var s = 'Age: $x'; // s的类型是?
var list = [1, 2]; // list的类型是?
var map = {'a': 1}; // map的类型是?
使用runtimeType验证你的答案。
创建一个工具函数,安全地将JSON值转换为目标类型:
T? safeCast<T>(dynamic value) {
// 实现类型安全转换
// 提示:使用 is 检查
}
使用Record和Pattern实现一个配置解析器:
// 解析命令行参数风格配置
// --port=8080 → ('port', 8080)
// --debug → ('debug', true)
// --name=MyApp → ('name', 'MyApp')
下一课:控制流与函数——深入学习条件、循环、函数参数、闭包和递归。