flutter Dart中产量和产量 * 之间的差异

yrdbyhpb  于 2022-12-05  发布在  Flutter
关注(0)|答案(4)|浏览(129)

我想知道这两者之间有什么区别。我在javascript上找到了这篇文章,Delegated yield (yield star, yield *) in generator functions
据我所知,yield*委托给另一个生成器,在另一个生成器停止生成值后,它会继续生成自己的值。
dart 方面的解释和例子会很有帮助。

oyjwcjzk

oyjwcjzk1#

我创建了一个dart pad链接来帮助人们进行实验:
Yield* 用于一次生成一个完整的可迭代值,而不使用循环。
这两个函数做的事情完全一样,根据开始值和结束值生成一个可迭代对象。

Iterable<int> getRangeIteration(int start, int finish) sync* {
  for(int i = start; i<= finish; i++){
  yield i;
  }
}

Iterable<int> getRangeRecursive(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    yield* getRangeRecursive(start + 1, finish);
  }
}

在第一个实现中(yield i)将隐含类型Iterable,它与函数的返回类型匹配。
现在如果在第二实现中代替

yield* getRangeRecursive(start + 1, finish);

如果我们做了

yield getRangeRecursive(start + 1, finish);

我们将得到一个编译器错误:

The type 'Iterable<Iterable<int>>' implied by the 'yield' expression must be assignable to 'Iterable<int>'.

正如你所看到的,yield用另一个Iterable〈〉 Package 了Iterable,这使得类型Iterable.不匹配函数的返回类型。
如果我们必须在不使用yield* 的情况下进行递归,我们将不得不这样做:

Iterable<int> getRangeRecursiveWithOutYieldStar(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    for (final val in getRangeRecursiveWithOutYieldStar(start + 1, finish)){
    yield val;
    }
  }
}

这是混乱和低效的。
所以我觉得在我看来,yield* 使另一个生成函数变平。
一些有用的资源:Generator Functions - Flutter in Focus video
中品:What are sync*, async*, yield and yield* in Dart?

f87krz0w

f87krz0w2#

使用下面的代码来理解为什么不使用yield* 进行递归编码效率很低。

Iterable<int> getRangeYield(int start, int end) sync* {
  if (start <= end) {
    yield start;
    for (final int val in getRangeYield(start + 1, end)) {
      yield val;
    }
  }
}

Iterable<int> getRangeYieldAnalysed(int start, int end) sync* {
  if (start <= end) {
    print('before start $start');
    yield start * 10;
    print('after start $start');
    for (final int val in getRangeYieldAnalysed(start + 1, end)) {
      print('before val $val');
      yield val * 100;
      print('after val $val');
    }
  }
}

Iterable<int> getRangeYieldStar(int start, int end) sync* {
  // same output as getRangeYield()
  if (start < end) {
    yield* getRangeYieldStar(start + 1, end);
  }
  yield start;
}

Iterable<int> getRangeYieldStarAnalysed(int start, int end) sync* {
  // same output as getRangeYield()
  print('generator $start started');
  if (start < end) {
    yield* getRangeYieldStarAnalysed(start + 1, end);
  }
  yield start;
  print('generator $start ended');
}

Iterable<int> getRangeForLoop(int start, int end) sync* {
  // same output as getRangeYield()
  for (int i = start; i <= end; i++) {
    yield i;
  }
}

void main() {
  Iterable<int> it = getRangeYieldStarAnalysed(1, 4);
  print('main range obtained');

  for(int element in it) {
    print('el $element');
  };
}
kadbb459

kadbb4593#

x1月0n1x日

它用于从异步或同步生成器发出值。

范例:

Stream<int> getStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

void main() {
  getStream(3).forEach(print);
}

输出:

1
2
3

yield*

它会将呼叫委派给另一个产生器,在该产生器停止产生值之后,它会继续产生自己的值。

范例:

Stream<int> getStream(int n) async* {
  if (n > 0) {  
    await Future.delayed(Duration(seconds: 1));
    yield n; 
    yield* getStream(n - 1); 
  }
}

void main() {
  getStream(3).forEach(print);
}

输出:

3
2 
1
oipij1gg

oipij1gg4#

简短回答

  • yield从Iterable或Stream返回值。
  • yield*用于递归调用其Iterable或Stream函数。

示例

让我们看看Generator Functions - Flutter in Focus视频中的一些例子。我们只看可迭代的例子,但流也是类似的。
表格1
这是一个从startfinish的迭代项。

Iterable<int> getRange(int start, int finish) sync* {
  for (int i = start; i <= finish; i++) {
    yield i;
  }
}

关键字yield返回每次迭代的下一个值。
表格2
现在,让我们重构这个函数,使其成为递归的。在外部,它仍然做着与前面相同的事情:

Iterable<int> getRange(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    for (final val in getRange(start + 1, finish)) {
      yield val;
    }
  }
}

这是可行的,但它很难阅读,并不是很有效,因为循环。
表格3
现在,让我们使用yield*(读作“yield星星”)再次对其进行重构:

Iterable<int> getRange(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    yield* getRange(start + 1, finish);
  }
}

它仍然是递归的,但现在更容易阅读,也更有效。

相关问题