Flutter循环访问控制插件loop_visitor的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter循环访问控制插件loop_visitor的使用

特性

  • 允许处理数据而无需积累(例如处理目录中的文件或大型文本文件中的行)。
  • 允许在调用者(循环)内部根据返回值(见VisitResult)对各种情况进行反应。
  • 允许在异步循环中使用同步(阻塞)或异步(非阻塞)迭代处理器(在与文件系统相关的操作中非常有用,当同时需要同步和异步版本时)。

使用方法

该示例可以在example/loop_visitor_example.dart中找到。

import 'dart:async';

import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:loop_visitor/loop_visitor.dart';

/// 应用特定的数据类
///
class DirEntryInfo {
  /// 文件数量限制
  ///
  static const int limit = 9;

  /// 目录条目
  ///
  FileSystemEntity? entity;

  /// 条目的类型
  ///
  /// 是的,`entity is File` 也可以工作,
  /// 但目的是展示更复杂的东西
  ///
  var type = FileSystemEntityType.notFound;
}

/// 过滤器(非阻塞)
///
Future<VisitResult> filterFiles(VisitParams<DirEntryInfo> params) async => filterFilesSync(params);

/// 过滤器(非阻塞)
///
VisitResult filterFilesSync(VisitParams<DirEntryInfo> params) {
  final myEntity = params.current;
  final entity = myEntity?.entity;
  final type = myEntity?.type;

  if ((entity == null) || (type != FileSystemEntityType.file)) {
    return VisitResult.skip;
  }

  final takenNo = params.takenNo + 1;
  print('$takenNo: ${entity.path}');

  final pileup = params.pileup as List<String>?;

  if (params.currentNo <= 1) {
    pileup?.clear();
  }

  pileup?.add(entity.path);

  return (takenNo >= DirEntryInfo.limit
      ? VisitResult.takeAndStop
      : VisitResult.take);
}

/// 非阻塞方式遍历目录条目
///
Future<int> getTopFiles(FileSystem fs, String dirName, List<String> pileup,
    VisitHandler<DirEntryInfo>? handler) async {
  var myEntity = DirEntryInfo();
  var result = VisitResult.take;
  var params = VisitParams<DirEntryInfo>(
      current: myEntity,
      pileup: pileup,
      isSyncCall: (handler is VisitHandlerSync));

  var dirList = fs.directory(dirName).list();

  await for (final entity in dirList) {
    ++params.currentNo;

    myEntity.entity = entity;
    myEntity.type =
        (params.isSyncCall ? entity.statSync() : await entity.stat()).type;

    if (handler != null) {
      if (params.isSyncCall) {
        result = handler(params) as VisitResult;
      } else {
        result = await handler(params);
      }
    }

    if (result.isTake) {
      ++params.takenNo;
    }

    if (result.isStop) {
      break;
    }
  }

  return params.takenNo;
}

/// 阻塞方式遍历目录条目
///
int getTopFilesSync(FileSystem fs, String dirName, List<String> pileup,
    VisitHandlerSync<DirEntryInfo>? handler) {
  var myEntity = DirEntryInfo();
  var result = VisitResult.take;
  var params = VisitParams<DirEntryInfo>(
      current: myEntity, pileup: pileup, isSyncCall: true);

  var dirList = fs.directory(dirName).listSync();

  for (final entity in dirList) {
    ++params.currentNo;

    myEntity.entity = entity;
    myEntity.type = entity.statSync().type;

    if (handler != null) {
      result = handler(params);
    }

    if (result.isTake) {
      ++params.takenNo;
    }

    if (result.isStop) {
      break;
    }
  }

  return params.takenNo;
}

/// 主入口点
///
Future<void> main(List<String> args) async {
  final fs = LocalFileSystem();

  final isSync = args.contains('-s');
  final argsEx = [...args.where((x) => !x.startsWith('-'))];

  if (argsEx.isEmpty) {
    argsEx.add(fs.currentDirectory.path);
  }

  var count = 0;
  var pileup = <String>[];

  for (final arg in argsEx) {
    print('''
--- 目录: "$arg"
''');

    if (isSync) {
      count = getTopFilesSync(fs, arg, pileup, filterFilesSync);
    } else {
      count = await getTopFiles(fs, arg, pileup, filterFiles);
    }

    print('''
总计: $count 文件,堆栈包含 ${pileup.length} 个路径:

$pileup
''');
  }
}

示例代码

import 'dart:async';

import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:loop_visitor/loop_visitor.dart';

/// 应用特定的数据类
///
class DirEntryInfo {
  /// 文件数量限制
  ///
  static const int limit = 9;

  /// 目录条目
  ///
  FileSystemEntity? entity;

  /// 条目的类型
  ///
  /// 是的,`entity is File` 也可以工作,
  /// 但目的是展示更复杂的东西
  ///
  var type = FileSystemEntityType.notFound;
}

/// 过滤器(非阻塞)
///
Future<VisitResult> filterFiles(VisitParams<DirEntryInfo> params) async => filterFilesSync(params);

/// 过滤器(非阻塞)
///
VisitResult filterFilesSync(VisitParams<DirEntryInfo> params) {
  final myEntity = params.current;
  final entity = myEntity?.entity;
  final type = myEntity?.type;

  if ((entity == null) || (type != FileSystemEntityType.file)) {
    return VisitResult.skip;
  }

  final takenNo = params.takenNo + 1;
  print('$takenNo: ${entity.path}');

  final pileup = params.pileup as List<String>?;

  if (params.currentNo <= 1) {
    pileup?.clear();
  }

  pileup?.add(entity.path);

  return (takenNo >= DirEntryInfo.limit
      ? VisitResult.takeAndStop
      : VisitResult.take);
}

/// 非阻塞方式遍历目录条目
///
Future<int> getTopFiles(FileSystem fs, String dirName, List<String> pileup,
    VisitHandler<DirEntryInfo>? handler) async {
  var myEntity = DirEntryInfo();
  var result = VisitResult.take;
  var params = VisitParams<DirEntryInfo>(
      current: myEntity,
      pileup: pileup,
      isSyncCall: (handler is VisitHandlerSync));

  var dirList = fs.directory(dirName).list();

  await for (final entity in dirList) {
    ++params.currentNo;

    myEntity.entity = entity;
    myEntity.type =
        (params.isSyncCall ? entity.statSync() : await entity.stat()).type;

    if (handler != null) {
      if (params.isSyncCall) {
        result = handler(params) as VisitResult;
      } else {
        result = await handler(params);
      }
    }

    if (result.isTake) {
      ++params.takenNo;
    }

    if (result.isStop) {
      break;
    }
  }

  return params.takenNo;
}

/// 阻塞方式遍历目录条目
///
int getTopFilesSync(FileSystem fs, String dirName, List<String> pileup,
    VisitHandlerSync<DirEntryInfo>? handler) {
  var myEntity = DirEntryInfo();
  var result = VisitResult.take;
  var params = VisitParams<DirEntryInfo>(
      current: myEntity, pileup: pileup, isSyncCall: true);

  var dirList = fs.directory(dirName).listSync();

  for (final entity in dirList) {
    ++params.currentNo;

    myEntity.entity = entity;
    myEntity.type = entity.statSync().type;

    if (handler != null) {
      result = handler(params);
    }

    if (result.isTake) {
      ++params.takenNo;
    }

    if (result.isStop) {
      break;
    }
  }

  return params.takenNo;
}

/// 主入口点
///
Future<void> main(List<String> args) async {
  final fs = LocalFileSystem();

  final isSync = args.contains('-s');
  final argsEx = [...args.where((x) => !x.startsWith('-'))];

  if (argsEx.isEmpty) {
    argsEx.add(fs.currentDirectory.path);
  }

  var count = 0;
  var pileup = <String>[];

  for (final arg in argsEx) {
    print('''
--- 目录: "$arg"
''');

    if (isSync) {
      count = getTopFilesSync(fs, arg, pileup, filterFilesSync);
    } else {
      count = await getTopFiles(fs, arg, pileup, filterFiles);
    }

    print('''
总计: $count 文件,堆栈包含 ${pileup.length} 个路径:

$pileup
''');
  }
}

更多关于Flutter循环访问控制插件loop_visitor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter循环访问控制插件loop_visitor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用loop_visitor插件的一个示例。loop_visitor插件通常用于在循环访问集合或列表时执行一些控制操作,比如中断循环、跳过某些元素等。不过,需要注意的是,loop_visitor并不是Flutter官方或广泛认知的插件,这里我们假设它提供了一些类似功能的API。

由于loop_visitor可能不是一个真实存在的Flutter插件(至少在我最后的知识更新时是这样),我将提供一个概念性的示例,展示如何在Flutter中手动实现类似的循环访问控制功能。

示例:手动实现循环访问控制

假设我们有一个列表,并希望在遍历这个列表时能够中断循环或跳过某些元素。我们可以使用Dart的迭代器和条件判断来实现这一点。

1. 创建一个Flutter项目

首先,确保你已经有一个Flutter项目。如果没有,可以使用以下命令创建一个新的Flutter项目:

flutter create loop_visitor_example
cd loop_visitor_example

2. 实现循环访问控制逻辑

lib/main.dart文件中,我们可以实现以下逻辑:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Loop Visitor Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> items = ['A', 'B', 'C', 'D', 'E'];

  void visitItems(List<String> items) {
    for (int i = 0; i < items.length; i++) {
      String item = items[i];
      
      // 假设我们有一个条件来中断循环
      if (item == 'C') {
        print('Breaking loop at item: $item');
        break;
      }
      
      // 假设我们有一个条件来跳过当前元素
      if (item == 'B') {
        print('Skipping item: $item');
        continue;
      }
      
      print('Visited item: $item');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Loop Visitor Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            visitItems(items);
          },
          child: Text('Visit Items'),
        ),
      ),
    );
  }
}

3. 运行应用

现在,你可以运行这个Flutter应用,点击按钮后,你会在控制台看到如下输出:

Visited item: A
Skipping item: B
Visited item: D
Breaking loop at item: C

解释

  • visitItems方法遍历items列表。
  • 如果当前元素是'C',则中断循环。
  • 如果当前元素是'B',则跳过当前元素,继续下一个迭代。
  • 其他情况下,打印当前元素。

通过这种方式,你可以在Flutter中实现类似于循环访问控制的功能,而无需依赖一个不存在的loop_visitor插件。如果你确实找到了一个名为loop_visitor的插件,并且它提供了类似的功能,那么你可以参考它的文档来集成和使用它。不过,基于现有的Dart和Flutter功能,上述示例已经展示了如何在循环中控制访问。

回到顶部