1.2 变量与数据类型

基础知识

在 Dart 中,变量是用来存储数据值的命名空间。每个变量都有一个类型,它决定了变量可以存储的数据种类。Dart 是一种强类型语言,这意味着变量在声明时通常需要指定类型,或者 Dart 会通过类型推断自动确定类型。Dart 支持以下几种内置数据类型:

  • Number (数值): Dart 中的数值类型分为两种:

    • int: 整数,不带小数点的数字,最大值取决于平台(通常是 64 位)。
    • double: 浮点数,带小数点的数字,符合 IEEE 754 标准。
      num 类型是 intdouble 的父类。
  • String (字符串): 表示文本序列。Dart 字符串是 UTF-16 编码的字符序列。可以使用单引号或双引号创建字符串。多行字符串可以使用三引号 '''"""

  • Boolean (布尔值): 表示真或假。只有两个值:truefalse。Dart 是一种类型安全的语言,不允许使用 10 来表示布尔值。

  • List (列表): 有序的、可索引的元素集合,类似于其他语言中的数组。Dart 中的 List 是一个泛型类型,可以指定列表中元素的类型。

  • Set (集合): 无序的、唯一的元素集合。Set 中的元素不能重复。

  • Map (映射): 键值对的集合,类似于其他语言中的字典或哈希表。Map 中的键是唯一的,值可以重复。

  • Runes: 用于表示 Unicode 字符序列。通常在处理表情符号或其他特殊字符时使用。

  • Symbols: 表示在 Dart 程序中声明的运算符或标识符。通常用于反射。

变量声明:

可以使用 var 关键字声明变量,Dart 会自动推断其类型。如果明确知道变量的类型,也可以直接指定类型。

dart
复制代码
var name = 'Bob'; // 类型推断为 String
String city = 'New York'; // 明确指定类型为 String
int age = 30; // 明确指定类型为 int
double price = 19.99; // 明确指定类型为 double
bool isActive = true; // 明确指定类型为 bool

// 声明一个 List
List<String> fruits = ['apple', 'banana', 'orange'];

// 声明一个 Set
Set<int> uniqueNumbers = {1, 2, 3, 1}; // 实际存储为 {1, 2, 3}

// 声明一个 Map
Map<String, String> capitals = {
  'USA': 'Washington D.C.',
  'Japan': 'Tokyo'
};

finalconst 关键字:

  • final: 用于声明只能赋值一次的变量。final 变量在第一次使用时初始化。
  • const: 用于声明编译时常量。const 变量在编译时就必须确定其值。
dart
复制代码
final String message = 'Hello'; // 运行时常量
const double PI = 3.14159; // 编译时常量

// const 也可以用于构造函数,创建编译时常量对象
const Point origin = Point(0, 0);

官方文档链接

Flutter 开发中的应用案例

在 Flutter 开发中,变量和数据类型无处不在,它们是构建 UI 和处理业务逻辑的基础。理解 Dart 的数据类型对于高效地使用 Flutter 至关重要。

案例:用户注册表单中的数据处理

假设我们正在开发一个用户注册表单,需要收集用户的姓名、年龄、邮箱和密码。这些信息将以不同的数据类型存储。

dart
复制代码
import 'package:flutter/material.dart';

class RegisterForm extends StatefulWidget {
  const RegisterForm({super.key});

  @override
  State<RegisterForm> createState() => _RegisterFormState();
}

class _RegisterFormState extends State<RegisterForm> {
  // 使用 late 关键字延迟初始化,或者在声明时赋初始值
  late String _name; // 存储用户姓名,String 类型
  late int _age; // 存储用户年龄,int 类型
  late String _email; // 存储用户邮箱,String 类型
  late String _password; // 存储用户密码,String 类型
  bool _agreeToTerms = false; // 存储用户是否同意条款,bool 类型

  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _ageController = TextEditingController();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _ageController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _submitForm() {
    setState(() {
      _name = _nameController.text;
      _age = int.tryParse(_ageController.text) ?? 0; // 尝试解析为 int,失败则为 0
      _email = _emailController.text;
      _password = _passwordController.text;
    });

    // 打印收集到的数据
    print('Name: $_name');
    print('Age: $_age');
    print('Email: $_email');
    print('Password: $_password');
    print('Agree to terms: $_agreeToTerms');

    // 可以在这里进行数据验证或发送到后端
    if (_agreeToTerms) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('注册成功!')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('请同意用户条款!')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('用户注册'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: <Widget>[
            TextField(
              controller: _nameController,
              decoration: const InputDecoration(labelText: '姓名'),
              keyboardType: TextInputType.name,
            ),
            TextField(
              controller: _ageController,
              decoration: const InputDecoration(labelText: '年龄'),
              keyboardType: TextInputType.number,
            ),
            TextField(
              controller: _emailController,
              decoration: const InputDecoration(labelText: '邮箱'),
              keyboardType: TextInputType.emailAddress,
            ),
            TextField(
              controller: _passwordController,
              decoration: const InputDecoration(labelText: '密码'),
              obscureText: true,
            ),
            Row(
              children: <Widget>[
                Checkbox(
                  value: _agreeToTerms,
                  onChanged: (bool? newValue) {
                    setState(() {
                      _agreeToTerms = newValue ?? false;
                    });
                  },
                ),
                const Text('我同意用户条款'),
              ],
            ),
            ElevatedButton(
              onPressed: _submitForm,
              child: const Text('注册'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(const MaterialApp(home: RegisterForm()));
}

案例分析:

  • late String _name;: 这里使用了 late 关键字,表示 _name 变量会在使用前被初始化。在 Flutter 的 StatefulWidget 中,通常会在 initState 或通过 TextEditingController 等方式在 build 方法中获取值。
  • int.tryParse(_ageController.text) ?? 0;: 这是一个将字符串转换为整数的例子。tryParse 方法会尝试将字符串解析为整数,如果解析失败则返回 null?? 是 Dart 的空值合并运算符,如果 tryParse 返回 null,则使用 0 作为默认值,这体现了 Dart 的空安全特性。
  • bool _agreeToTerms = false;: 布尔类型变量用于存储用户是否同意条款的状态。
  • TextEditingController: Flutter 中用于控制 TextField 文本内容的控制器。final 关键字用于声明这些控制器,因为它们在创建后不会再被重新赋值。
  • List<Widget>: 在 ColumnRow 中,children 属性接受一个 List<Widget>,这展示了 Dart 中 List 类型在构建 UI 布局时的应用。

这个案例展示了如何在 Flutter 应用中声明和使用不同数据类型的变量,以及如何处理用户输入并进行类型转换。理解这些基本概念是构建任何 Flutter 应用的基础。