当前位置:首页 > 文章列表 > 文章 > 软件教程 > Dart - 认识Records

Dart - 认识Records

2026-08-20 23:44:37 0浏览 收藏

第一章:没有 Records 的日子,我们经历了什么?

作为一名 Dart/Flutter 开发者,你一定经历过这样的“至暗时刻”:

Dart - 认识Records

你编写了一个简易的工具函数,比如解析经纬度,或者从API响应中提取数据。你的逻辑清晰明了,代码也仅有寥寥数行。然而,当你写到return语句时,却陷入了困境。

“我有两个数据要返回,但我只能返回一个对象。”

在 Dart 3 引入 Records 之前,为了解决这个问题,我们通常只有三种选择。而这三种选择,坦白说,都很难受。

痛点一:为了喝杯奶,专门养头牛(定义专用类)

这是最“规范”,但也是最啰嗦的做法。

假设我们需要解析一个颜色字符串(如 #FF0033),并返回 R、G、B 三个整数值。在旧时代的 Dart 中,为了保持类型安全,我们需要专门定义一个类:

// 1. 先得定义一个类,还要写构造函数、toString、甚至重写 == 和 hashCode
class RGBColor {
  final int r;
  final int g;
  final int b;

  RGBColor(this.r, this.g, this.b);
}

// 2. 然后才能在函数里用它
RGBColor parseColor(String hex) {
  // 假装这里有一段解析逻辑...
  return RGBColor(255, 0, 51);
}

void main() {
  final color = parseColor('#FF0033');
  print('Red: ${color.r}');
}

为什么痛苦?

  • 代码膨胀:你的项目里会充斥着大量像 RGBColorUserInfoResultLocationData 这样的一次性类。它们可能只在一个函数里用了一次,但你却不得不为它们写上 5-10 行的定义代码。
  • 命名困难:给这些临时类起名字是编程界最大的难题之一。ParsedColorColorResultColorDTO?想想都头大。

痛点二:在那“裸奔”的类型安全(使用 List 或 Map)

如果你嫌定义类太麻烦,你可能会选择“偷懒”,使用 List 或者 Map 来打包数据。这就像是在代码里“裸奔”,虽然凉快,但是极其危险。

// 返回 List,但谁知道 index 0 是 R 还是 B?
Listint> parseColor(String hex) {
  return [255, 0, 51];
}

void main() {
  final color = parseColor('#FF0033');
  
  // 痛点:完全没有语义,必须靠脑子记下标
  final red = color[0]; 
  
  // 痛点:越界风险,如果函数改了把 alpha 通道加进去,这里可能就崩了
  final blue = color[2]; 
}

或者用 Map

MapString, int> parseColor(String hex) {
  return {'r': 255, 'g': 0, 'b': 51};
}

void main() {
  final color = parseColor('#FF0033');
  
  // 痛点:手写字符串 Key,一旦手抖写成 'R',编译不报错,运行直接崩
  final red = color['r']; 
  
  // 痛点:返回类型是 int? (可空),你不得不到处写 ! 或者 ??
  print(red! + 10);
}

为什么痛苦?

  • 类型丢失:编译器帮不了你,你得自己保证下标和 Key 的正确性。
  • 可读性差color[0] 是什么?一个月后你自己都忘了。

痛点三:引入第三方库的尴尬(Tuple)

有些开发者会引入 package:tuple。这确实解决了一些问题,但体验依然不够原生。

import 'package:tuple/tuple.dart';

Tuple3int, int, int> parseColor(String hex) {
  return const Tuple3(255, 0, 51);
}

void main() {
  final color = parseColor('#FF0033');
  
  // 痛点:item1, item2 是什么鬼?完全没有语义!
  print('Red: ${color.item1}');
}

为什么痛苦?

  • 语义不明:看着满屏的 item1item2,代码的可维护性直线下降。

总结

在没有 Records 的时代,我们在**“繁琐的安全性”(写类)和“危险的便捷性”**(用 List/Map)之间反复横跳。

我们真正需要的是这样一种东西:

  1. 轻量:不需要专门定义一个类。
  2. 安全:编译器能知道里面有什么类型。
  3. 清晰:字段得有名字,别让我猜 item1 是什么。

于是,Dart 3 带着 Records 来了。它完美地填补了这个空缺。那么它到底长什么样?又该如何使用?

请看下一章:《Records 的极简美学:像写函数参数一样定义数据》


第二章:Records 的极简美学 —— 像写函数参数一样定义数据

在上一章的“吐槽大会”结束后,我们终于迎来了主角:Records (记录)

Dart 团队在设计 Records 时,并没有发明一套古怪的新语法,而是做了一个非常天才的决定:直接复用函数的参数语法

这就意味着,只要你会写函数,你就会写 Records。

1. 两种形态:哑巴盒子与标签盒子

Records 分为两种形态,分别对应我们熟悉的“位置参数”和“命名参数”。

形态一:位置记录 (Positional Records)

这对应了上一章提到的 Tuple 库,或者数组。

  • 什么时候用? 当数据之间有明显的顺序关系,且大家都约定俗成时(比如经纬度、数学坐标、RGB 颜色)。
  • 怎么写? 直接用括号包裹类型或值。
// 定义类型:(类型1, 类型2)
(double, double) getLocation() {
  return (39.9, 116.4); // 返回值
}

void main() {
  var location = getLocation();
  
  // 访问方式:使用 $1, $2, $3...
  print('Lat: ${location.$1}'); 
  print('Lon: ${location.$2}');
}

评价:简单粗暴,但如果有 5 个字段,千万别用这个,否则下周你自己都不知道 $4 是什么。

形态二:命名记录 (Named Records) —— 推荐!

这才是 Records 的杀手锏,它几乎完美替代了简单的 DTO 类。

  • 什么时候用? 绝大多数场景!特别是当你需要返回多个字段,且希望字段有清晰含义时。
  • 怎么写? 用花括号 {} 包裹,就像写命名参数一样。
// 定义类型:({类型 名字, 类型 名字})
({int r, int g, int b}) parseColor() {
  // 返回值:带上名字,顺序无所谓
  return (r: 255, b: 51, g: 0); 
}

void main() {
  var color = parseColor();
  
  // 访问方式:直接用名字!类型极其安全!
  print('Red: ${color.r}'); 
  print('Green: ${color.g}');
}

评价:这简直就是**“匿名类”**的究极形态。没有 class 声明,没有构造函数,但有名字、有类型检查。


2. 终极奥义:模式匹配与解构

如果只是能通过 .r 访问属性,Records 还不够性感。Dart 3 同步带来的 模式匹配 (Pattern Matching) 才是让代码起飞的关键。

试想一下,你收到了一个包裹,过去你得先把包裹拿进屋(赋值给变量),然后再拆开(访问属性)。可现在,当你拿到包裹的那一刻,包裹就能“自动解体”,里面的东西直接飞到你的手中。

这就是 解构 (Destructuring)

解构位置记录

var (lat, lon) = getLocation();
// 此时,lat 和 lon 已经是可用的 double 变量了
print('Lat: $lat'); 

解构命名记录 (最爽的语法)

// 语法糖:如果变量名和属性名一样,连“: var”都可以省!
var (:r, :g, :b) = parseColor();

print('Red: $r'); // 直接使用局部变量 r


3. Before & After:代码整容现场

让我们回到第一章那个解析颜色的痛点,看看用 Records 重写后有多清爽。

⛔️ Before (旧时代 - 定义类):

// 冗余代码:为了这点醋,包了顿饺子
class RGBColor {
  final int r;
  final int g;
  final int b;
  RGBColor(this.r, this.g, this.b);
}

RGBColor parseColor(String hex) {
  // 逻辑...
  return RGBColor(255, 0, 51);
}

void main() {
  var c = parseColor('#FF0033');
  print(c.r);
}

✅ After (Dart 3 - Records):

// 只有逻辑,没有废话
({int r, int g, int b}) parseColor(String hex) {
  return (r: 255, g: 0, b: 51);
}

void main() {
  // 一行解构,直接使用
  final (:r, :g, :b) = parseColor('#FF0033');
  print(r);
}

变化总结

  1. 代码行数:从 15 行减少到 8 行。
  2. 样板代码:0 行。没有 class,没有构造函数。
  3. 可读性:语义完全保留,类型安全完全保留。

4. 总结:Records 不是万能的

读到这里,你可能想把项目里所有的类都换成 Records。请冷静!

Records 的定位非常明确:数据的“胶水”和“信封”

  • 请尽情使用 Records

  • 函数需要返回多个值时。

  • 需要临时组合几个变量传给 UI 组件时。

  • 处理 Map 的复合键时(比如 Map)。

  • 请坚持使用 Class

  • 当你的数据需要行为(即方法/函数)时。

  • 当你的数据结构非常庞大(超过 4-5 个字段)时。

  • 当这是你 App 的核心领域模型(如 User, Order)时,因为 Records 不能继承,也没有名字,重构起来可能会有麻烦。

一句话总结:Dart 3 的 Records,让我们终于可以优雅地解决“为了两个数据专门写一个类”的历史难题。它是 Dart 变得更现代、更高效的重要拼图。

Swift 减少指令数量的编码 TipsSwift 减少指令数量的编码 Tips
上一篇
Swift 减少指令数量的编码 Tips
Dart - 认识Sealed(密封类)
下一篇
Dart - 认识Sealed(密封类)
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ljg-skills -
    ljg-skills
    ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
    5043次使用
  • MELO音乐 - AI 音乐生成平台,支持多模态创作能力
    MELO音乐
    MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
    4575次使用
  • UniScribe - AI 免费在线音视频转文字平台
    UniScribe
    UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
    4529次使用
  • 剧云 - 免费 AI 智能中文剧本创作平台
    剧云
    剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
    4782次使用
  • 万象有声 - AI 一站式有声内容创作平台
    万象有声
    万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
    4734次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码