变量声明
在 Dart 中,有多种方式声明变量:
var 关键字
var name = 'Bob'; // 类型推断为 String
var age = 20; // 类型推断为 int
显式类型声明
String name = 'Bob';
int age = 20;
double height = 1.75;
bool isStudent = true;
dynamic 和 Object
dynamic value = 'Hello';
value = 123; // 可以改变类型
Object obj = 'Hello';
obj = 123; // 也可以改变类型
final 和 const
final name = 'Bob'; // 运行时常量
const pi = 3.14159; // 编译时常量
基本数据类型
数值型 (Numbers)
int
int age = 20;
int hexValue = 0xDEADBEEF;
double
double height = 1.75;
double exponents = 1.42e5;
字符串 (String)
字符串声明
String name = 'Bob';
String message = "Hello World";
字符串插值
String name = 'Bob';
String greeting = 'Hello, $name!';
String calculation = 'The sum is ${2 + 2}';
多行字符串
String multiLine = '''
This is a
multi-line string
in Dart.
''';
布尔型 (bool)
bool isStudent = true;
bool isWorking = false;
列表 (List)
List<int> numbers = [1, 2, 3, 4, 5];
var fruits = ['apple', 'banana', 'orange'];
集合 (Set)
Set<String> uniqueNames = {'Bob', 'Alice', 'Charlie'};
var numbers = {1, 2, 3, 4, 5};
映射 (Map)
Map<String, int> ages = {
'Bob': 20,
'Alice': 25,
'Charlie': 30,
};
var scores = {
'math': 90,
'history': 85,
'science': 95,
};
类型转换
字符串转换
// 字符串转数字
int.parse('123'); // 123
double.parse('1.23'); // 1.23
// 数字转字符串
123.toString(); // '123'
3.14159.toStringAsFixed(2); // '3.14'
数值转换
// int 转 double
int age = 20;
double ageDouble = age.toDouble();
// double 转 int
double price = 9.99;
int priceInt = price.toInt();
空安全
Dart 2.12 引入了空安全特性:
// 可空类型
String? nullableName; // 可以为 null
int? age; // 可以为 null
// 非空类型
String nonNullName = 'Bob'; // 不能为 null
int nonNullAge = 20; // 不能为 null
// 空值检查
String? name;
print(name?.length); // 安全调用
print(name!.length); // 强制非空
类型判断
is 关键字
var value = 'Hello';
if (value is String) {
print('Value is a String');
}
runtimeType 属性
print(value.runtimeType); // 打印运行时类型
常见用法示例
void main() {
// 基本变量声明和使用
String name = 'Bob';
int age = 20;
double height = 1.75;
bool isStudent = true;
// 字符串插值
print('Name: $name, Age: $age, Height: $height, Student: $isStudent');
// 列表操作
var numbers = [1, 2, 3, 4, 5];
numbers.add(6);
numbers.remove(1);
print('Numbers: $numbers');
// Map操作
var person = {
'name': 'Bob',
'age': 20,
'height': 1.75,
};
person['weight'] = 65;
print('Person: $person');
// 空安全示例
String? nullableName;
print('Nullable name: ${nullableName ?? 'Unknown'}');
// 类型转换
var numberString = '123';
var parsedNumber = int.parse(numberString);
print('Parsed number: $parsedNumber');
}
注意事项
- 优先使用 var 声明变量,除非需要明确指定类型
- const 用于编译时常量,final 用于运行时常量
- 注意空安全特性,合理使用可空类型
- 避免滥用 dynamic 类型
- 使用类型推断时要注意上下文
最佳实践
- 变量命名使用小驼峰命名法
- 常量命名使用小驼峰命名法
- 优先使用字符串插值而不是字符串连接
- 合理使用 final 关键字提高代码的可维护性
- 显式声明API中的参数和返回类型
实战案例:给 JSON 的每个值”猜”一个 Dart 类型
ygking_json_to_dart_model 里有个 _getFieldType(dynamic value, String key) 方法,干的事就是”看一个 JSON 值,猜它该是什么 Dart 类型”。这是变量和数据类型最真实的应用场景:
// 逻辑示意(_getFieldType 的核心):
if (value is int) return 'int';
if (value is double) return 'double';
if (value is bool) return 'bool';
if (value is String) return 'String';
if (value is List) return 'List<...>';
if (value is Map) return key.capitalize(); // 嵌套对象→生成新类
然后生成的字段全部加 ?:int? age;、String? name;。为什么?因为 JSON 是外部输入,{"age": 25} 这次有 age,下次可能就没有。如果生成 int age;(非空),fromJson 里 json['age'] 一返回 null,直接抛异常。可空类型在这里不是”语法特性”,是”对不确定性的诚实”。
还有个 Dart 特有的坑:JSON 数字不分 int 和 double,25 和 25.0 在 JSON 里都是 number。Dart 的 json.decode 会把 25 解成 int、25.0 解成 double。我的 _getFieldType 必须分开判断——如果偷懒全按 num 生成,调用方每次用都要 as int,体验很差。类型的精度要跟数据源对齐,数据源分 int/double,你的类型就得跟着分。
dynamic vs var vs 明确类型,我的习惯是:能明确就明确(StringBuffer buffer = StringBuffer()),真不确定才 dynamic(final dynamic jsonData)。var 我反而少用——var 是”编译器帮我推”,dynamic 是”我明确表示不知道”。这两个心态完全不同,混用是很多隐性 bug 的来源。
总结
Dart 的变量和数据类型系统既灵活又严谨,通过合理使用可以写出更安全、更易维护的代码。类型是 Dart 里最便宜的文档——把类型写清楚,很多 bug 在运行前就被拦下了。
