flutter 如何在Dart中迭代流

vhipe2zx  于 2023-05-19  发布在  Flutter
关注(0)|答案(2)|浏览(188)

我正在学习与 dart 绳,经过多年的Python。我对流有点困惑,如果有任何其他特定的解决方案,我可以使用我的特定情况。
我正在构建一个API驱动的应用程序,我需要动态填充ListView,而不需要等待所有HTTP调用完成。目前我使用的是一个Stream,它用yields作为返回值填充List:
就像这样:

var scraperList = List<Api> ();

Stream<List<Api>> get getFiles (String id) async* {
    var res = await http.post('${baseUrl}/folder/list/{id}');
    if (res.statusCode == 200) {
      var jsonResult = jsonDecode(res.body);
      jsonResult = jsonResult['content'];
      List<dynamic> body = jsonResult;
      List<Api> result = body.map((dynamic item) => ApiModel.apiFiles(item),).toList();
}

现在,这就是我迷失的地方,因为API充当了一种文件/文件夹存储,如果它们是“文件”,我需要产生结果,并使用文件夹的ID重复调用,并获得该文件夹中的“文件”,并继续这样做,直到我递归地获得每个文件夹中的所有文件。
关键是我想继续提供流,并在结果到达时获得结果,而不需要等待所有调用完成。
我现在不明白的是

// THIS IS THE PART I NEED TO UNDERSTAND YET
      for (item in result){
        if (item.type == 'file'){
          yield filelist.add(0, item);}
        else { I NEED TO MAKE A CALL AGAIN TO THIS FUNCTION TO GET THE FOLDER CONTENT
             THE CALL AGAIN }

我如何迭代这个API,递归地获取每个文件夹中的所有文件,并继续提供该流?有没有更好的办法?在Python中,有很多方法可以在类之间共享列表等等,但我仍然对如何在Dart中动态实现这一点感到困惑。

wljmcqd8

wljmcqd81#

你需要的是屈服和等待
检查这个

import 'dart:async';

void main() {

  final folder1 = Future.value({"a","b","c","d"});
  final folder2 = Future.value({"a","b","c","d",folder1});
  final folder3 = {"a","b","c","d",folder1,folder2}; //what you get initially

  Stream printElement(list) async*{

     for(dynamic element in list){

      if(element is String){
        yield element;
       }else{
        yield* printElement(
        await(element));  //make your http call here for your nested folder
        }

     };
  }

  printElement(folder3).listen((element){
      print(element);
  });

}

您也可以使用更多类型安全代码与Either来自dartz package

import 'dart:async';
import 'package:dartz/dartz.dart';

class MyFile{

  final String fileName ;

  MyFile(this.fileName);

  @override
  String toString() {
    return this.fileName;
  }
}

class MYFolder{

  final String folderName;
  final List<Either<Future<MYFolder>,MyFile>> files; //files can be Either file or Future of folder from HTTP

  MYFolder(this.folderName, this.files);

  @override
  String toString() {
    return this.folderName;
  }
}

void main() {

  //leaf folders

  final foldera = MYFolder("foldera",[Right(MyFile("a")),Right(MyFile("a")),Right(MyFile("a")),Right(MyFile("a"))]);
  final folderb = MYFolder("folderb",[Right(MyFile("b")),Right(MyFile("b")),Right(MyFile("b")),Right(MyFile("b"))]);
  final folderc = MYFolder("folderc",[Right(MyFile("c")),Right(MyFile("c")),Right(MyFile("c")),Right(MyFile("c"))]);
  final folderd = MYFolder("folderd",[Right(MyFile("d")),Right(MyFile("d")),Right(MyFile("d")),Right(MyFile("d"))]);

  //                    ...foldera
  //                   - folderb
  //        -  folder1
  //
  //folder3 -  folder2
  //                  ... folderc
  //                  - folderd
  //
  // --triple dot notation for folding elements in lists ,it is just a shortcut for populating lists

  final  folder1 = Future.value(MYFolder("folder1", [...foldera.files,Left(Future.value(folderb))]));
  final folder2 = Future.value(MYFolder("folder2", [...folderc.files, Left(Future.value(folderd))]));
  final folder3 = MYFolder("folder3",[Left(Future.value(folder1)),Left(Future.value(folder2))]); //what you get initially

  Stream printFilesIn(MYFolder folder) async*{

    print("Current folder is $folder");

     for(Either file in folder.files){
      if(file is Right){
        yield file.value;
      }else{
        yield* printFilesIn(
        await(file as Left).value); //make your http call here for your nested folder
        }
      };
  }

  printFilesIn(folder3).listen(print);

}
7rfyedvj

7rfyedvj2#

虽然这个答案对你来说可能太晚了(3年后),但它仍然可以帮助其他人在未来遇到类似的问题。
Saed可能误解了您的意图,他提供的答案是将Iterator转换为Stream,而不是迭代Stream(可能相当于将Stream转换为Iterator)。
据我所知,这件事可能办不到。但是有一个非常相似的解决方案--使用StreamIterator。它具有与Iterator类似的接口。不同的是它的方法是异步的。例如,您应该使用await streamIterator.moveNext()而不是iterator.moveNext()
Stream转换为StreamIterator非常简单,只需使用final streamIterator = StreamIterator(yourStream);即可。
IteratorStreamIterator之间可能很难共享相同的功能,因为Iterator具有同步方法。目前,我通过将Iterable转换为Stream,然后将其转换为StreamIterator来实现这一点:
final streamIterator = StreamIterator(Stream.fromIterable(iterable));
请让我知道,如果你有任何更优雅的解决方案或任何意见,我的答案。

相关问题