Вопрос

This code trips me up. In this code the takeWhile makes sense - take up debits, reducing the balance while the balance is positive. The problem is with this code nothing happens. No calls to balance.debit() are made and I guess the reason is takeWhile filtering happens lazily.

I can ensure that it gets called by tacking on a toList() call, but that seems wasteful as a list is not really needed.

  • What is a better way to do this?
  • Is takeWhile not the right tool for this job?

Code follows:

class Balance {
  Balance(this._balance);
  double _balance;
  debit(double amount) {
    print('Debiting $amount');
    return (_balance -= amount);
  }
}

main() {
  final balance = new Balance(3.0);
  final debits = [ 1.0, 2.0, 3.0 ];
  debits.takeWhile((debit) => balance.debit(debit) > 0);

  //////////////////////
  //debits
  //  .takeWhile((debit) => balance.debit(debit) > 0)
  //  .toList();
}
Это было полезно?

Решение

No, takeWhile is not the right tool for this job.

As you noticed, it is lazy. It is intended to create a new iterable, and it only does something if you actually use that iterable. Here, you are not interested in the result at all, so you just want the "while" part, and don't care about the "take". Alternative:

for (debit in debits) {
  if (balance.debit(debit) < 0) break;
}

I even find it easier to read.

Другие советы

This behaviour is described in the api doc of Iterable.takeWhile :

The filtering happens lazily.

To enforce evaluation you can use .length, .forEach((_){}), .toList() (...) on the result of takeWhile(...)

You are right, this is because it is lazy evaluated. You need something that enforces iterating over the result. If you don't want to create a list you could also do something like:

var r = debits.takeWhile((debit) => balance.debit(debit) > 0);
for(var x in r) {
  // print(x);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top