Dart: Dart 变量与数据类型 — 五种声明方式与内置类型

最后更新:2026-08-26

变量是数据的容器,类型是容器的形状 — 选对容器,代码才安全。

1. 你将学到


2. 一个开发者的真实故事

(1) 痛点:随意声明变量导致运行时崩溃

Bob 在开发 DataPipeline 的早期版本时,所有变量都用 var 声明,还经常中途修改变量类型。一次重构中,他误将 int orderCount 改为 String orderCount,编译没报错(dynamic 类型),但运行时 orderCount * price 抛出异常,导致处理 500,000 条订单的批处理任务中断,报表延迟 4 小时交付。

(2) 类型安全的解法

Dart 提供了从宽松到严格的一系列声明方式:const(编译时常量)→ final(运行时常量)→ var(推断类型)→ late(延迟初始化)→ dynamic(动态类型)。合理选用能让编译器帮你找 bug。

DART
// Best practice for DataPipeline configuration
const int maxRecords = 1000000;       // Compile-time constant
final String pipelineName;             // Runtime constant (set once)
var processedCount = 0;                // Inferred as int, mutable
late String outputPath;                // Initialized later
// dynamic should be avoided if possible
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

(3) 收益


3. 五种声明方式

(1) 声明方式决策树

100%
graph LR
  subgraph Declarations
    A[var] --> B[Type inference]
    C[final] --> D[Runtime constant]
    E[const] --> F[Compile-time constant]
    G[late] --> H[Lazy initialization]
    I[dynamic] --> J[Dynamic type]
  end
  subgraph Built-in Types
    K[int] --- L[double]
    M[String] --- N[bool]
  end
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:var — 类型推断

DART
void main() {
  var name = 'DataPipeline';   // Inferred as String
  var count = 1000;            // Inferred as int
  var rate = 0.08;             // Inferred as double

  // Can reassign same type
  name = 'Analytics';          // OK - still String
  count = 2000;                // OK - still int

  // Cannot change type
  // count = 'two thousand';   // Compile error!
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:final — 运行时常量

DART
void main() {
  // Set once at runtime
  final DateTime startTime = DateTime.now();
  final String configPath = '/etc/datapipeline/config.yaml';

  // Cannot reassign
  // configPath = '/other/path';  // Compile error!

  // final with collection - contents can change
  final List``<String>`` sources = ['orders.csv', 'products.csv'];
  sources.add('customers.csv');   // OK - modifying contents
  // sources = ['new_list'];       // Error - cannot reassign reference
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:const — 编译时常量

DART
void main() {
  // Must be known at compile time
  const int maxRecords = 1000000;
  const double taxRate = 0.08;
  const String version = '1.0.0';

  // const collections are deeply immutable
  const List``<String>`` formats = ['json', 'csv', 'html'];
  // formats.add('xml');  // Error! Cannot modify const list

  // const constructor
  const config = PipelineConfig(batchSize: 10000);
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:late — 延迟初始化

DART
class DataPipeline {
  late String outputPath;  // Will be set later

  void configure(String path) {
    outputPath = path;
  }

  late final int maxRecords = _loadMaxRecords();  // Computed on first access

  int _loadMaxRecords() {
    print('Loading max records config...');
    return 1000000;
  }
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:dynamic — 动态类型

DART
void main() {
  dynamic value = 'hello';   // String
  value = 42;                // OK - now int
  value = [1, 2, 3];        // OK - now List

  // No compile-time type checking - risky!
  // value.nonExistentMethod();  // No compile error, runtime crash

  // Prefer Object? over dynamic when you need flexibility
  Object? safeValue = 'test';
  // safeValue.nonExistentMethod();  // Compile error - safer
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

(2) 五种声明方式对比

声明方式 类型 可变 初始化时机 安全性 使用场景
const 编译时确定 不可变 声明时 最高 配置常量、枚举值
final 运行时确定 不可变 声明时或构造函数 高 运行时配置、注入值
var 推断 可变 声明时 中 局部变量、计数器
late 显式标注 可变 延迟 中 延迟初始化字段
dynamic 运行时 可变 任意 低 JSON 解析、互操作

4. 内置类型详解

(1) 数值类型

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:int 与 double

DART
void main() {
  int orderCount = 1500;
  double totalAmount = 52500.75;
  num genericNum = 42;      // num is supertype of int and double
  genericNum = 3.14;        // OK - num accepts both

  // Arithmetic operations
  double avgOrderValue = totalAmount / orderCount;
  int roundedDown = totalAmount.toInt();

  // Convenient methods
  print(totalAmount.toStringAsFixed(2));  // 52500.75
  print(orderCount.isEven);              // false (1500 is even, true)
  print(orderCount.clamp(0, 1000));      // 1000 (clamped to max)
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
类型 范围 用途
int 64-bit (JS 限制时不同) 计数、索引
double 64-bit IEEE 754 金额、比例
num int + double 的父类型 通用数值

(2) String 类型

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:String 插值与操作

DART
void main() {
  // String interpolation
  String product = 'DataPipeline';
  int users = 5000;
  print('$product has $users users');               // Simple interpolation
  print('Revenue: ${users * 99} USD');              // Expression interpolation
  print('Average: ${(125000 / users).toStringAsFixed(2)} USD');

  // Multi-line strings
  String description = '''
  DataPipeline - E-Commerce Analytics Tool
  Processes up to 1,000,000 orders per batch
  Supports JSON, CSV, and HTML output formats
  ''';

  // Raw strings (no escape processing)
  String path = r'C:\Users\Bob\data\orders.csv';
  String regex = r'\d{4}-\d{2}-\d{2}';  // Date pattern

  // Useful methods
  String raw = '  Hello, World!  ';
  print(raw.trim());                  // 'Hello, World!'
  print(raw.toUpperCase());           // '  HELLO, WORLD!  '
  print('USD 1,500.00'.replaceAll(',', ''));  // 'USD 1500.00'
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
特性 语法 示例
简单插值 $variable '$name'
表达式插值 ${expr} '${a + b}'
多行字符串 '''...''' 三引号
原始字符串 r'...' r'\n' 保持原样

(3) bool 类型

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:布尔值与条件

DART
void main() {
  bool isProduction = true;
  bool isDebug = false;

  // Dart requires explicit bool in conditions
  int count = 0;
  // if (count) {}  // Error! Must be bool
  if (count > 0) {  // OK - explicit comparison
    print('Has records');
  }

  // Logical operators
  bool shouldProcess = isProduction && !isDebug;
  bool hasData = count > 0 || isProduction;
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

5. 类型推断与显式标注

(1) 最佳实践

DART
// Good - let the compiler infer for local variables
var name = 'DataPipeline';     // Inferred String
var count = 100;               // Inferred int
var items = ``<String>``[];        // Explicit generic, inferred List

// Good - explicit type for public API
String get displayName => name;
int get maxCapacity => 1000000;

// Good - final for values that don't change
final startTime = DateTime.now();

// Avoid - unnecessary explicit type on locals
// String name = 'DataPipeline';  // Redundant
// int count = 100;               // Redundant
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
场景 推荐 原因
局部变量 var / final 减少冗余,推断足够
公开 API 显式标注 文档清晰,接口稳定
集合泛型 显式泛型 避免推断为 `List`````
构造函数参数 显式标注 契约清晰

6. Bob 场景:DataPipeline 配置变量

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:配置变量设计

DART
// DataPipeline configuration constants
const String appName = 'DataPipeline';
const int defaultBatchSize = 10000;
const double defaultTaxRate = 0.08;

// Runtime configuration
class PipelineConfig {
  final String version;
  final int batchSize;
  final String outputFormat;

  PipelineConfig({
    this.version = '1.0.0',
    this.batchSize = defaultBatchSize,
    this.outputFormat = 'json',
  });

  @override
  String toString() =>
      '$appName v$version | Batch: $batchSize | Format: $outputFormat';
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

7. 完整示例:DataPipeline 变量声明实战

DART
// ============================================
// DataPipeline Variable Declaration Demo
// Shows proper use of all declaration types
// ============================================

// Compile-time constants - never change across runs
const String appName = 'DataPipeline';
const int maxRecords = 1000000;
const double taxRate = 0.08;
const List``<String>`` supportedFormats = ['json', 'csv', 'html'];

class Order {
  final String id;          // Runtime constant after construction
  final double amount;      // Runtime constant after construction
  late String status;       // Will be set by processing logic

  Order({required this.id, required this.amount});

  double get tax => amount * taxRate;
  double get total => amount + tax;

  String get formattedAmount =>
      '\$${amount.toStringAsFixed(2)} USD';
}

class DataPipeline {
  final String name;
  var processedCount = 0;              // Mutable counter
  late final DateTime startTime;       // Set on first run

  DataPipeline({required this.name});

  void start() {
    startTime = DateTime.now();
    print('$appName started at $startTime');
  }

  void processOrder(Order order) {
    processedCount++;
    order.status = 'processed';
    print('Order ${order.id}: ${order.formattedAmount} '
        '(tax: \$${order.tax.toStringAsFixed(2)} USD)');
  }

  void printSummary() {
    print('\n=== Summary ===');
    print('Pipeline: $name');
    print('Processed: $processedCount orders');
    print('Capacity: $processedCount / $maxRecords');
  }
}

void main() {
  final pipeline = DataPipeline(name: 'E-Commerce Analytics');
  pipeline.start();

  final orders = [
    Order(id: 'ORD-001', amount: 1500.00),
    Order(id: 'ORD-002', amount: 3250.50),
    Order(id: 'ORD-003', amount: 890.25),
  ];

  for (final order in orders) {
    pipeline.processOrder(order);
  }

  pipeline.printSummary();
}
TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

输出:

TEXT 📖 仅展示
DataPipeline started at 2024-01-15 10:30:00.000
Order ORD-001: $1500.00 USD (tax: $120.00 USD)
Order ORD-002: $3250.50 USD (tax: $260.04 USD)
Order ORD-003: $890.25 USD (tax: $71.22 USD)

=== Summary ===
Pipeline: E-Commerce Analytics
Processed: 3 orders
Capacity: 3 / 1000000

❓ 常见问题

Q:var 和 final 该用哪个? A:如果变量不会重新赋值,优先用 final。如果需要修改,用 var。Dart 官方 lint 规则 prefer_final_locals 推荐优先使用 final。

Q:const 和 final 的区别是什么? A:const 是编译时常量,值在编译时必须确定;final 是运行时常量,只能赋值一次但值可以在运行时计算。DateTime.now() 不能用 const。

Q:什么时候用 late? A:当变量无法在声明时初始化,但你能保证在使用前一定会初始化时用 late。常见场景:依赖注入、构造后配置。误用会导致运行时 LateInitializationError。

Q:dynamic 和 Object? 有什么区别? A:dynamic 关闭所有类型检查,编译器不校验任何方法调用;Object? 保留类型检查,只能调用 Object 的方法。优先用 Object?。

Q:Dart 的 int 在 Web 和 VM 上一样吗? A:不完全一样。Dart VM 上 int 是 64 位整数;编译为 JS 时,int 受 JS Number 限制(53 位精度)。大数运算需注意。

Q:String 可以用单引号还是双引号? A:都可以,效果完全一样。Dart 官方风格指南推荐单引号,除非字符串内包含单引号时才用双引号。

Q:num 类型什么时候用? A:当你需要同时接受 int 和 double 的参数或变量时用 num。num 是 int 和 double 的父类型,支持基本算术运算。


📖 小节


📝 作业

  1. 基础题(难度⭐):声明以下变量:一个 const 的应用名称、一个 final 的当前时间、一个 var 的计数器,分别打印它们的值和类型。
  2. 进阶题(难度⭐⭐):写一个函数,接受 num 类型参数,返回该数值的 USD 格式字符串(如 formatUSD(1500.5) 返回 "$1,500.50 USD")。注意 int 和 double 的处理。
  3. 挑战题(难度⭐⭐⭐):设计一个 Config 类,用 late 延迟初始化数据库连接字符串,用 const 定义默认值,用 final 保存从环境变量读取的配置,展示三种声明方式的协作。

← 上一课 | 下一课 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏