ZetCode

Dart 中的通配符变量

最后修改于 2025 年 5 月 25 日

Dart 3.8 引入了通配符变量,这是一项强大的新功能,用于模式匹配和解构。本教程将探讨如何在各种上下文中将下划线 (_) 用作通配符,以忽略您不需要的值。

通配符变量概述

在 Dart 中,通配符变量由下划线字符 (_) 表示。它们允许您在模式中匹配和忽略特定值,从而使您的代码更简洁、更具表现力。此功能在解构赋值、模式匹配和函数参数中特别有用,在这些场景中某些值是不需要的。

用例 描述 示例
解构 解包时忽略特定元素 var (x, _, z) = (1, 2, 3);
模式匹配 在模式中匹配但忽略值 case [_, int middle, _]
函数参数 忽略未使用的参数 void log(String msg, _)
循环变量 迭代中忽略值 for (var (_, value) in data)

上表总结了 Dart 中通配符变量的主要用例。通配符用途广泛,可应用于各种上下文以提高代码的可读性和可维护性。它们可以帮助您专注于有意义的值,同时清楚地表明哪些值被有意忽略。

基本通配符用法

通配符变量最常用于解构赋值,您只想从集合或记录中提取特定值。下划线字符充当视觉指示器,表明某些值被故意忽略。

basic_wildcard.dart
void main() {
  // Tuple destructuring with wildcard
  var (name, _, age) = ('Alice', 'alice@example.com', 30);
  print('$name is $age years old');
  
  // List destructuring
  var numbers = [1, 2, 3, 4, 5];
  var [first, _, third, ..._] = numbers;
  print('First: $first, Third: $third');
  
  // Map destructuring (with pattern matching)
  var user = {'name': 'Bob', 'email': 'bob@example.com', 'age': 25};
  var {'name': userName, 'age': userAge} = user;
  print('$userName is $userAge');
}

在这些示例中,通配符用于跳过元组的电子邮件提取,以及忽略列表中的偶数元素。map 解构显示了一种替代方法,您可以在其中仅提取所需字段,而无需显式忽略其他字段。通配符可以立即清楚地表明哪些值被刻意从解构操作中省略。

$ dart run basic_wildcard.dart
Alice is 30 years old
First: 1, Third: 3
Bob is 25

使用通配符进行模式匹配

当与 Dart 的模式匹配功能结合使用时,通配符会变得特别强大。它们允许您匹配复杂结构,同时只关注对您的逻辑重要的部分。

pattern_matching.dart
void main() {
  // Matching lists with wildcards
  var matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
  ];
  
  for (var row in matrix) {
    switch (row) {
      case [_, var middle, _]:
        print('Middle value: $middle');
    }
  }
  
  // Matching records with nested wildcards
  var shapes = [
    ('circle', 10.0),
    ('square', 5.0),
    ('triangle', (3.0, 4.0, 5.0))
  ];
  
  for (var shape in shapes) {
    switch (shape) {
      case ('triangle', (_, var b, _)):
        print('Triangle middle side: $b');
      case (var type, _):
        print('Shape type: $type');
    }
  }
}

第一个示例演示了通配符如何帮助仅从矩阵的每一行中提取中间元素。第二个示例显示了更高级的用法,包括嵌套模式,其中我们使用通配符忽略形状名称(当我们只关心三角形尺寸时),然后忽略所有尺寸(当我们只想要形状类型时)。这种选择性匹配使代码既简洁又富有表现力。

$ dart run pattern_matching.dart
Middle value: 2
Middle value: 5
Middle value: 8
Shape type: circle
Shape type: square
Triangle middle side: 4.0

函数参数和通配符

当您需要接受但实际上不使用的参数时,通配符可以清理函数签名。这在遵循特定接口但不需要所有提供参数的回调函数中很常见。

function_parameters.dart
void main() {
  // Function with ignored parameter
  void logError(String message, _) {
    print('ERROR: $message');
  }
  
  logError('File not found', 404);
  
  // Callback with ignored parameters
  void processItems(List<String> items, void callback(String, _)) {
    for (var i = 0; i < items.length; i++) {
      callback(items[i], i);
    }
  }
  
  processItems(['Apple', 'Banana', 'Cherry'], (item, _) {
    print('Processing $item');
  });
  
  // Higher-order function with wildcard
  void Function(String) makeLogger(String prefix) {
    return (String message) => print('$prefix: $message');
  }
  
  var debugLog = makeLogger('DEBUG');
  debugLog('Initializing');
}

logError 函数显示了一个简单的情况,我们接受但忽略了第二个参数。processItems 示例演示了一个更实际的场景,其中回调函数接收了一个它不需要的索引参数。在这些情况下使用通配符比使用未使用的命名参数更能清晰地表达代码的意图。当处理函数组合时,高阶函数示例显示了通配符如何帮助维护干净的函数签名。

$ dart run function_parameters.dart
ERROR: File not found
Processing Apple
Processing Banana
Processing Cherry
DEBUG: Initializing

高级通配符模式

通配符可以与其他 Dart 语言功能结合使用,以创建仍然可读且可维护的复杂模式。这些高级模式在处理复杂数据结构时尤其有用。

advanced_patterns.dart
void main() {
  // Nested destructuring with wildcards
  var complexData = [
    ('header', {'content': 'Hello', 'meta': 123}),
    ('footer', {'content': 'Goodbye', 'meta': 456})
  ];
  
  for (var (_, {'content': message}) in complexData) {
    print(message);
  }
  
  // Wildcards in switch expressions
  var responses = [
    (200, 'OK', {'data': 'content'}),
    (404, 'Not Found', null),
    (500, 'Error', {'error': 'message'})
  ];
  
  for (var response in responses) {
    var status = switch (response) {
      (200, _, _) => 'Success',
      (404, _, _) => 'Missing',
      (_, _, {'error': _}) => 'Error',
      _ => 'Unknown'
    };
    print(status);
  }
}

第一个示例显示了嵌套模式匹配,我们仅从作为元组一部分的 map 中提取 content 字段。switch 表达式演示了通配符如何帮助仅根据状态码对响应进行分类,同时忽略其他字段。即使在处理复杂数据结构时,这些模式也能保持清晰。

$ dart run advanced_patterns.dart
Hello
Goodbye
Success
Missing
Error

虽然通配符功能强大,但应谨慎使用以保持代码清晰。通配符的主要目的是显式忽略那些否则会被视为意外未使用的值。过度使用通配符会使得理解数据结构的哪些部分实际上在逻辑中使用变得更加困难。

来源

Dart 语言:模式
Dart 语言演进

Dart 3.8 中的通配符变量提供了一种干净、富有表现力的方式来处理结构化数据,同时只关注有意义的值。通过使用下划线字符显式忽略不需要的值,您可以编写更简洁的模式匹配代码,清晰地传达其意图。当与 Dart 的其他模式匹配功能结合使用时,此功能尤其强大。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Dart 教程