如何在Dart中进行惰性评估?

Mac*_* Sz 5 language-features dart

是否有本机(支持语言)的惰性评估语法?像lazy valScala一样。

我已经浏览了文档,但找不到任何东西。只有一章关于“延迟加载库”,但这不是我要的。

基于这项研究,我倾向于相信(如果我错了,请纠正我)当前没有这种事情。但是,也许您知道将提供该功能的任何计划或功能请求?还是Dart团队考虑并拒绝了它?

如果确实对此没有本地支持,那么实现惰性评估的最佳实践(最佳语法)是什么?一个例子将不胜感激。

编辑:

我正在寻找的功能的优点与其他语言的实现几乎相同:Scalalazy valC#Lazy<T>Hack的__Memorize属性

  1. 简洁的语法
  2. 延迟计算直到需要该值
  3. 缓存结果(需要的惰性)
  4. 不要打破纯粹的功能范式(下面的解释)

一个简单的例子:

class Fibonacci {

  final int n;
  int _res = null;

  int get result {
    if (null == _res) {
      _res = _compute(this.n);
    }
    return _res;
  }

  Fibonacci(this.n);

  int _compute(n) {
    // ...
  }
}

main(List<String> args) async {
  print(new Fibonacci(5).result);
  print(new Fibonacci(9).result);
}
Run Code Online (Sandbox Code Playgroud)

吸气剂非常冗长,并且具有重复的代码。此外,我无法创建构造函数,const因为_res必须根据需要计算缓存变量。我想像一下,如果我具有类似Scala的lazy功能,那么我也将拥有支持常量构造函数的语言支持。这是由于以下事实:延迟的求值_res参照透明的不会造成妨碍

class Fibonacci {

  final int n;
  int lazy result => _compute(this.n);

  const Fibonacci(this.n);  // notice the `const`

  int _compute(n) {
    // ...
  }
}

main(List<String> args) async {
  // now these makes more sense:
  print(const Fibonacci(5).result);
  print(const Fibonacci(9).result);
}
Run Code Online (Sandbox Code Playgroud)

reh*_*001 19

2021 年更新

\n

从 2.12 版本开始,延迟初始化现在已成为 dart 的一部分。

\n

late只需在变量声明中添加修饰符即可

\n
late MyClass obj = MyClass();\n
Run Code Online (Sandbox Code Playgroud)\n

并且这个对象只有在第一次使用的时候才会被初始化。

\n

来自文档

\n

Dart 2.12 添加了late修饰符,它有两个用例:

\n
    \n
  1. 声明一个不可为空的变量,\xe2\x80\x99s 在声明后初始化。
  2. \n
  3. 延迟初始化变量。
  4. \n
\n

在此处查看示例:\n https://dartpad.dev/?id=50f143391193a2d0b8dc74a5b85e79e3&null_safety=true

\n
late MyClass obj = MyClass();\n
Run Code Online (Sandbox Code Playgroud)\n

A仅在显示“第一条消息”后才会初始化此类。

\n


Gün*_*uer 5

更新2

来自@lrn 的评论 - 使用 Expando 进行缓存使其与 const 一起工作:

class Lazy<T> {
  static final _cache = new Expando();
  final Function _func;
  const Lazy(this._func);
  T call() {
    var result = _cache[this];
    if (identical(this, result)) return null;
    if (result != null) return result;
    result = _func();
    _cache[this] = (result == null) ? this : result;
    return result;
  }
}


defaultFunc() {
  print("Default Function Called");
  return 42;
}
main([args, function = const Lazy(defaultFunc)]) {
  print(function());
  print(function());
}
Run Code Online (Sandbox Code Playgroud)

在 DartPad 中尝试

更新

可重用Lazy<T>在 Dart 中可能如下所示,但它也不适用于 const,并且如果计算需要引用实例成员 (this.xxx),则不能在字段初始值设定项中使用。

void main() {
  var sc = new SomeClass();
  print('new');
  print(sc.v);
}

class SomeClass {
  var _v  = new Lazy<int>(() {
    print('x');
    return 10;
  });
  int get v => _v();
}

class Lazy<T> {
  final Function _func;
  bool _isEvaluated = false;
  Lazy(this._func);
  T _value;
  T call() {
    if(!_isEvaluated) {
      if(_func != null) {
        _value = _func();
      }
      _isEvaluated = true;
    }
    return _value;
  }
}
Run Code Online (Sandbox Code Playgroud)

DartPad 中尝试

原来的

http://matt.might.net/articles/implementing-laziness/ 的Dart 版本使用闭包进行惰性求值:

void main() {
  var x = () { 
    print ("foo"); 
    return 10; 
  }();
  print("bar");
  print(x);
  // will print foo, then bar then 10.
  print('===');
  // But, the following Scala program:
  x = () { 
    print("foo"); 
    return 10; 
  };
  print ("bar");
  print (x());
  // will print bar, then foo, then 10, since it delays the computation of x until it’s actually needed.
}
Run Code Online (Sandbox Code Playgroud)

DartPad 中尝试

  • 有一种方法可以同时获得延迟缓存评估和常量:使用全局“Expando”来保存缓存值,而不是将它们放在对象上。见:https://dartpad.dartlang.org/8a668690499074a1b62f (3认同)