Dart系列 --- 记录类型 (元组)

记录类型 (元组)是 Dart 3 中引入的新功能。

您还需要在 pubspec.yaml 文件中将 Dart 3 设置为 sdk:sdk: ">=3.0.0 <4.0.0"

前言

在 dart 2 中,当您想要将多个对象捆绑到一个值中多个对象时,您有 2 个选择。

1:创建一个包含对象作为属性的类

arduino 复制代码
class DataClass {  
  final int number;  
  final String string; 
  final double float;   
  const DataClass(this.number, this.string, this.float);
}

如果对象过于太多的话,这个策略就会显得很冗长

2:使用集合 ,例如ListMap ,或Set

ini 复制代码
List<Object> collection = [0, 'a', 0.0];

问题是该选项不是类型安全的:

ListMapSet 可以存储单一类型(List<int>List<String>List<double>)。 如果您需要多种类型,您通常会回退到 List<Object>

记录类型 (元组) 在dart3的使用

csharp 复制代码
(int, String, double) record = (0, 'a', 0.0); 
// Or without type annotationfinal 
record = (0, 'a', 0.0);

上面的代码创建了一条包含 intStringdouble 的元组,无需创建类或使用集合。

定义一个元组看起来与定义一个List完全相同,但用 () 而不是 []

然后,您可以通过索引访问每个值(从 1 开始 ),前缀为 $

ini 复制代码
(int, String, double) record =  (0, 'a', 0.0);
int number = record.$1;
String string = record.$2;
double float = record.$3;

您还可以为元组中的每个值指定一个名称

csharp 复制代码
({double float, int number, String string}) 
record = (number: 1, string: 'a', float: 2.0); 
// Or without type annotationfinal
record = (number: 1, string: 'a', float: 2.0);

通过这样做,元组就像没有名称的类一样:您可以从其名称访问每个字段。

csharp 复制代码
{double float, int number, String string}) record = (number: 1, string: 'a', float: 2.0); 
int number = record.number;
String string = record.string
double float = record.float;

还可以使用命名字段和未命名字段的组合:

csharp 复制代码
(int, double, {String string}) record = (1, string: 'a', 2.0);

此外,您还可以在一行中解构所有元组:

csharp 复制代码
final (number, string, float) = record;

使用元组

我们使用新的元组类型将 Card 构造为 SuitRank 的组合:

ini 复制代码
typedef Card = (Suit, Rank);

这个新的 () 语法定义了一个 Card(在本例中为 Tuple,因为它由 2 种类型组成)。 在 dart 3.0 之前,这是不可能的

注意typedef允许为类型指定另一个名称,以后每次使用Card而无需继续写(Suit, Rank) ,使得代码更加清晰。

这样可以避免为简单类型创建类 。在 dart 3.0 之前,相同的结果需要 class:

kotlin 复制代码
/// Before dart 3.0
class Card { 
final Suit suit; 
final Rank rank;  
const Card(this.suit, this.rank);
}

使用这个新模型(sealedtypedef 元组):

ini 复制代码
 Card = (Suit(), Rank());

元组的其他作用

Records 解锁的另一项功能是返回多个值

函数现在可以返回一条元组,可以访问 2 个或更多值

在 Dart 3 之前,这需要创建另一个新类,并返回类来实现。

解构元组

Dart 3 还允许解构值,在可以将调用的结果直接分配给变量pickCard(也称为绑定 ):

ini 复制代码
final (card, deck) = pickCard;

上面的代码定义了 2 个新变量:carddeck全部写在一行中! 在 Dart 3 之前,这个过程要复杂得多

Switch 表达式和解构

可以将 switch 用作表达式(而不仅仅是一条语句)。

意味着可以将调用switch的结果直接分配给变量

此外,在switch情况下也可以进行解构,因此您可以在一行中进行模式匹配并提取值.

比如我们现在可以使用模式匹配从 Hand 中提取卡片,我们使用新的switch表达式语法以及解构元组

php 复制代码
String howManyCards = switch (hand) { 
 /// Match `ThreeCards` and extract each card (`card1`, `card2`, `card3`)    ThreeCards(cards: (final card1, final card2, final card3)) => "3 cards: $card1, $card2, $card3",   
  /// Match `TwoCards` and extract each card (`card1`, `card2`) 
 TwoCards(cards: (final card1, final card2)) => "2 cards: $card1, $card2",   
 /// Match `OneCard` and extract it (`singleCard`) 
 OneCard(card: final singleCard) => "1 card: $singleCard",   
 /// Match `NoCard` (all cases are matched ✅)  
 NoCard() => "Ain't no card 🙌",
};
  • howManyCards 是一个新变量,包含switch 表达式的结果(不再是简单的语句☝️)
  • switch使用模式匹配来检查是否涵盖了所有可能的情况(否则会出现编译时错误)并从每个子类型中提取值
  • 在每个模式中,我们提取cards/card值并对其进行解构(将这些值分配给新变量card1, card2, card3, singleCard)

增强的 if 语句

新语法还允许if语句中使用模式匹配

php 复制代码
/// Pattern match and destructure directly inside `if` cases 
if (hand case OneCard(card: final singleCard)) {  
   print("1 card: $singleCard");
}

元组的使用规范

元组表达式

元组是使用元组表达式创建的:

less 复制代码
var record = (number: 123, name: "Main", type: "Street");

这与函数调用参数列表的语法相同(带有 可选的 const 开头)。有一些语法限制 没有被语法捕获。如果元组具有以下任何一项,则这是一个编译时错误:

  • 同一字段名称多次。
  • 只有一个位置字段并且没有尾随逗号。
  • 无字段且尾随逗号。 不允许使用表达式(,)
  • 名为 hashCoderuntimeTypenoSuchMethodtoString 的字段。
  • 以下划线开头的字段名称。
  • 与位置的合成 getter 名称冲突的字段名称 场地。 例如:('pos', $1: 'named')因为命名字段"$1"是 与第一个位置字段的 getter 发生碰撞。

为了避免括号表达式产生歧义,元组带有只有一个位置字段必须有尾随逗号:

ini 复制代码
var number = (123);  // The number 123.
var record = (123,); // A record containing the number 123.

表达式()指的是没有字段的常量空元组。

元组类型注释

在类型系统中,每条元组都有对应的元组类型。元组类型 看起来类似于函数类型的参数列表。该类型被包围 括号并且可能包含逗号分隔的位置字段:

arduino 复制代码
(int, String name, bool) triple;

每个字段都是一个类型注释和一个可选名称,该名称没有意义,但 对于文档目的很有用。

命名字段位于类型和名称对的大括号分隔部分内:

arduino 复制代码
({int n, String s}) pair;

元组类型可以同时具有位置字段和命名字段:

dart 复制代码
(bool, num, {int n, String s}) quad;

如果元组类型具有以下任何一种,则这是一个编译时错误:

  • 同一字段名称多次。 即使其中一个或两个都成立,也是如此 碰撞场是位置性的。我们可以允许与位置发生碰撞 字段名称,因为它们仅用于文档,但我们不允许这样做 因为它令人困惑并且没有用。
  • 只有一个位置字段并且没有尾随逗号。 这并不含糊, 因为 Dart 中没有带括号的类型表达式。但禁止 这与元组表达式是对称的,并且有可能 稍后支持括号以在类型表达式中进行分组。
  • 名为 hashCoderuntimeTypenoSuchMethodtoString 的字段。
  • 以下划线开头的字段名称。
  • 与位置的合成 getter 名称冲突的字段名称 场地。 例如:(int, $1: int)因为命名字段"$1"是碰撞 与第一个位置字段的吸气剂。

有关更多详细元组的规范信息,您可以阅读元组的规范信息一文

相关推荐
崔庆才丨静觅13 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606114 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了14 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅14 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅14 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
renke336414 小时前
Flutter for OpenHarmony:色彩捕手——基于HSL色轮与感知色差的交互式色觉训练系统
flutter
崔庆才丨静觅15 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment15 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅15 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊15 小时前
jwt介绍
前端