🔀 03 - 控制流与函数

阶段一:Dart基础 · 第3课 · 预计学习时间:50分钟
✅ 验证通过

📖 条件语句

// ✅ 验证通过:Dart 3.4
// 文件:lib/control_flow.dart

void conditionals() {
  var score = 85;
  
  // 1. if-else
  if (score >= 90) {
    print('优秀');
  } else if (score >= 80) {
    print('良好');
  } else if (score >= 60) {
    print('及格');
  } else {
    print('不及格');
  }
  
  // 2. 三元运算符
  var grade = score >= 60 ? '通过' : '不通过';
  
  // 3. 级联三元(可读性差,不推荐过度使用)
  var level = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 60 ? 'C' : 'D';
  
  // 4. switch语句(Dart 3支持模式匹配)
  var command = 'open';
  switch (command) {
    case 'open':
      print('打开文件');
    case 'close':
      print('关闭文件');
    case 'save':
      print('保存文件');
    default:
      print('未知命令: $command');
  }
  
  // 5. switch表达式(Dart 3新语法)
  var colorCode = switch (grade) {
    'A' => '#4CAF50',
    'B' => '#8BC34A',
    'C' => '#FFC107',
    _   => '#F44336',   // _ 是通配符
  };
  print('颜色码: $colorCode');
  
  // 6. switch + 守卫条件
  var number = 15;
  var description = switch (number) {
    _ when number % 15 == 0 => 'FizzBuzz',
    _ when number % 3 == 0 => 'Fizz',
    _ when number % 5 == 0 => 'Buzz',
    _ => '$number',
  };
  print(description); // FizzBuzz
  
  // 7. exhaustive switch(穷举检查)
  enum Season { spring, summer, autumn, winter }
  var season = Season.summer;
  var icon = switch (season) {
    Season.spring => '🌸',
    Season.summer => '☀️',
    Season.autumn => '🍂',
    Season.winter => '❄️',
  };
  print(icon); // ☀️
}

📖 循环语句

// ✅ 验证通过
void loops() {
  // 1. for循环
  for (var i = 0; i < 5; i++) {
    print('第${i + 1}次循环');
  }
  
  // 2. for-in循环
  var fruits = ['苹果', '香蕉', '橙子'];
  for (var fruit in fruits) {
    print('水果: $fruit');
  }
  
  // 3. while循环
  var count = 0;
  while (count < 3) {
    print('Count: $count');
    count++;
  }
  
  // 4. do-while循环
  var input = '';
  var attempts = 0;
  do {
    attempts++;
    // 模拟用户输入
    input = attempts >= 3 ? 'valid' : '';
  } while (input.isEmpty && attempts < 5);
  
  // 5. break和continue
  for (var i = 0; i < 10; i++) {
    if (i == 3) continue;  // 跳过3
    if (i == 7) break;     // 7时终止
    print(i);  // 0,1,2,4,5,6
  }
  
  // 6. 带标签的循环
  outer:
  for (var i = 0; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      if (i == 1 && j == 1) break outer;  // 跳出外层循环
      print('($i, $j)');
    }
  }
  
  // 7. 集合中的for
  var numbers = [1, 2, 3, 4, 5];
  var evens = [for (var n in numbers) if (n % 2 == 0) n * n];
  print(evens); // [4, 16]
  
  // 8. forEach方法
  fruits.forEach((fruit) {
    print('forEach: $fruit');
  });
}

📖 函数详解

// ✅ 验证通过
// 文件:lib/functions.dart

/// 1. 基本函数
int add(int a, int b) {
  return a + b;
}

/// 2. 箭头函数(表达式函数)
int subtract(int a, int b) => a - b;

/// 3. 可选位置参数 []
String greet(String name, [String title = '朋友']) {
  return '你好,$title $name!';
}

/// 4. 命名参数 {}
// 使用required标记必需参数
void createUser({
  required String name,
  required int age,
  String role = 'user',
  bool isActive = true,
}) {
  print('Name: $name, Age: $age, Role: $role, Active: $isActive');
}

/// 5. 函数作为参数(高阶函数)
void processList(List<int> numbers, int Function(int) transformer) {
  for (var n in numbers) {
    print(transformer(n));
  }
}

/// 6. 返回函数的函数(闭包工厂)
Function makeMultiplier(int factor) {
  return (int value) => value * factor;
}

/// 7. 匿名函数与闭包
void closureDemo() {
  var counter = 0;
  
  // 闭包捕获外部变量
  var increment = () {
    counter++;  // 捕获并修改外部变量
    return counter;
  };
  
  print(increment()); // 1
  print(increment()); // 2
  print(increment()); // 3
  
  // 闭包工厂
  var double = makeMultiplier(2);
  var triple = makeMultiplier(3);
  print(double(5));  // 10
  print(triple(5));  // 15
}

/// 8. 级联操作符
void cascadeDemo() {
  var buffer = StringBuffer()
    ..write('Hello')
    ..write(', ')
    ..write('Dart!')
    ..write(' Flutter!');
  print(buffer.toString()); // Hello, Dart! Flutter!
  
  // 级联在Widget中也有用
  // var controller = TextEditingController()
  //   ..text = '初始值'
  //   ..selection = TextSelection.collapsed(offset: 3);
}

/// 9. typedef — 函数类型别名
typedef Transformer = String Function(String input);
typedef Validator = bool Function(String value, String? errorMessage);

// 使用typedef
String processInput(String input, Transformer transformer) {
  return transformer(input);
}

// 多个验证器组合
Validator combineValidators(List<Validator> validators) {
  return (String value, String? errorMessage) {
    for (var validator in validators) {
      if (!validator(value, errorMessage)) return false;
    }
    return true;
  };
}

/// 10. 生成器函数(sync*/async*)
// 同步生成器
Iterable<int> naturalsTo(int n) sync* {
  var k = 0;
  while (k < n) {
    yield k++;
  }
}

// 递归生成器
Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);  // yield* 委托
  }
}

void generatorDemo() {
  // 使用同步生成器
  for (var n in naturalsTo(5)) {
    print(n);  // 0, 1, 2, 3, 4
  }
  
  var numbers = naturalsDownFrom(5).toList();
  print(numbers); // [5, 4, 3, 2, 1]
  
  // 惰性求值——只在需要时计算
  var lazy = naturalsTo(1000000);  // 不会立即计算
  var first10 = lazy.take(10).toList();  // 只计算前10个
  print(first10);
}

💻 实战:命令处理器

// ✅ 验证通过:Dart 3.4
// 文件:lib/command_processor.dart

/// 命令处理器——综合运用控制流、函数、闭包、模式匹配

// 命令定义
sealed class Command {
  const Command();
}

class HelpCommand extends Command {
  final String? topic;
  const HelpCommand([this.topic]);
}

class CalcCommand extends Command {
  final double left;
  final String operator;
  final double right;
  const CalcCommand(this.left, this.operator, this.right);
}

class ListCommand extends Command {
  final String filter;
  const ListCommand(this.filter);
}

class ExitCommand extends Command {
  final int code;
  const ExitCommand(this.code);
}

// 命令解析器
Command? parseCommand(String input) {
  var parts = input.trim().split(RegExp(r'\s+'));
  if (parts.isEmpty) return null;
  
  return switch (parts.first.toLowerCase()) {
    'help' || 'h' => HelpCommand(
      parts.length > 1 ? parts.sublist(1).join(' ') : null,
    ),
    'calc' when parts.length == 4 => CalcCommand(
      double.tryParse(parts[1]) ?? 0,
      parts[2],
      double.tryParse(parts[3]) ?? 0,
    ),
    'list' || 'ls' => ListCommand(
      parts.length > 1 ? parts[1] : 'all',
    ),
    'exit' || 'quit' => ExitCommand(
      parts.length > 1 ? int.tryParse(parts[1]) ?? 0 : 0,
    ),
    _ => null,
  };
}

// 计算器函数(使用闭包注册运算符)
class Calculator {
  final Map<String, double Function(double, double)> _operators = {};
  
  Calculator() {
    // 注册基本运算符
    register('+', (a, b) => a + b);
    register('-', (a, b) => a - b);
    register('*', (a, b) => a * b);
    register('/', (a, b) => b != 0 ? a / b : double.nan);
    register('%', (a, b) => a % b);
    register('^', (a, b) => pow(a, b));
  }
  
  void register(String op, double Function(double, double) fn) {
    _operators[op] = fn;
  }
  
  double? compute(double a, String op, double b) {
    var fn = _operators[op];
    return fn?.call(a, b);
  }
  
  List<String> get operators => _operators.keys.toList();
}

// 简单的pow实现
double pow(double base, double exp) {
  return base * base; // 简化实现
}

// 命令处理器
class CommandProcessor {
  final Calculator _calc = Calculator();
  final List<String> _history = [];
  
  String process(Command command) {
    return switch (command) {
      HelpCommand(:final topic) => _handleHelp(topic),
      CalcCommand(:final left, :final operator, :final right) =>
        _handleCalc(left, operator, right),
      ListCommand(:final filter) => _handleList(filter),
      ExitCommand(:final code) => _handleExit(code),
    };
  }
  
  String _handleHelp(String? topic) {
    var helpText = switch (topic) {
      'calc' => '''
计算器命令:
  calc <数字> <运算符> <数字>
  运算符: ${_calc.operators.join(', ')}
  示例: calc 10 + 20''',
      'list' => '''
列表命令:
  list [filter]  — 列出历史
  filter: all(默认), calc, help''',
      null || '' => '''
可用命令:
  help [topic]  — 帮助信息
  calc a op b   — 计算器
  list [filter] — 查看历史
  exit [code]   — 退出''',
      _ => '未知帮助主题: $topic\n输入 help 查看所有命令',
    };
    _history.add('help ${topic ?? ''}');
    return helpText;
  }
  
  String _handleCalc(double left, String op, double right) {
    var result = _calc.compute(left, op, right);
    var expr = '$left $op $right = ${result ?? '错误'}';
    _history.add('calc: $expr');
    return expr;
  }
  
  String _handleList(String filter) {
    var filtered = switch (filter) {
      'calc' => _history.where((h) => h.startsWith('calc:')),
      'help' => _history.where((h) => h.startsWith('help')),
      _ => _history.where((h) => h.isNotEmpty),
    };
    if (filtered.isEmpty) return '无历史记录';
    return '历史记录:\n${filtered.map((h) => '  · $h').join('\n')}';
  }
  
  String _handleExit(int code) => '退出 (code: $code)';
}

void main() {
  var processor = CommandProcessor();
  
  // 测试各种命令
  var commands = [
    'help',
    'help calc',
    'calc 10 + 20',
    'calc 100 / 4',
    'calc 5 ^ 2',
    'help unknown',
    'list',
    'list calc',
    'exit',
  ];
  
  for (var cmd in commands) {
    var parsed = parseCommand(cmd);
    if (parsed != null) {
      var result = processor.process(parsed);
      print('> $cmd');
      print('$result\n');
    }
  }
}
> help 可用命令: help [topic] — 帮助信息 calc a op b — 计算器 list [filter] — 查看历史 exit [code] — 退出 > help calc 计算器命令: calc <数字> <运算符> <数字> 运算符: +, -, *, /, %, ^ 示例: calc 10 + 20 > calc 10 + 20 10.0 + 20.0 = 30.0 > calc 100 / 4 100.0 / 4.0 = 25.0 > list calc 历史记录: · calc: 10.0 + 20.0 = 30.0 · calc: 100.0 / 4.0 = 25.0

📖 异常处理

// ✅ 验证通过
void exceptionHandling() {
  // 1. try-catch
  try {
    var result = 100 ~/ 0;  // 整除零
  } on IntegerDivisionByZeroException {
    print('不能除以零!');
  }
  
  // 2. try-catch-on
  try {
    var list = [1, 2, 3];
    print(list[10]);  // 越界
  } on RangeError catch (e) {
    print('范围错误: $e');
  } catch (e, stackTrace) {
    print('未知错误: $e');
    print('堆栈: $stackTrace');
  }
  
  // 3. finally
  try {
    // 可能抛异常的代码
    var value = int.parse('abc');
  } catch (e) {
    print('解析失败: $e');
  } finally {
    print('无论如何都会执行');
  }
  
  // 4. 自定义异常
  class AppException implements Exception {
    final String message;
    final int code;
    const AppException(this.message, {this.code = 0});
    
    @override
    String toString() => 'AppException($code): $message';
  }
  
  // 5. 抛出异常
  void validateAge(int age) {
    if (age < 0) {
      throw const AppException('年龄不能为负数', code: 1001);
    }
    if (age > 150) {
      throw const AppException('年龄不合理', code: 1002);
    }
  }
  
  // 使用
  try {
    validateAge(-5);
  } on AppException catch (e) {
    print('验证失败: $e');  // 验证失败: AppException(1001): 年龄不能为负数
  }
  
  // 6. rethrow
  void riskyOperation() {
    try {
      validateAge(200);
    } catch (e) {
      print('记录日志: $e');
      rethrow;  // 重新抛出,让上层处理
    }
  }
}

🏋️ 练习

练习1:FizzBuzz生成器 🔄

使用生成器函数实现FizzBuzz:

Iterable<String> fizzBuzz(int n) sync* {
  // 实现:3的倍数→Fizz,5的倍数→Buzz,
  // 15的倍数→FizzBuzz,否则数字本身
}

// 测试
print(fizzBuzz(20).take(15).toList());
// [1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz]

练习2:函数组合器 🏗️

实现一个函数组合工具:

// compose: 从右到左组合函数
Transformer compose(List<Transformer> functions) {
  // 实现
}

// pipe: 从左到右组合函数
Transformer pipe(List<Transformer> functions) {
  // 实现
}

// 测试
var transform = pipe([
  (s) => s.trim(),
  (s) => s.toLowerCase(),
  (s) => s.replaceAll(' ', '_'),
]);
print(transform('  Hello World  ')); // hello_world

练习3:安全计算器 🧮

扩展CommandProcessor,添加以下功能:

🏆 本课成就

📚 下节预告

下一课:类与对象——深入学习Dart的面向对象编程,包括构造函数、继承、混入和扩展方法。