如何在 Dart 中进行惰性求值?
How to do lazy evaluation in Dart?
是否有本地(支持语言)惰性求值语法?类似于 Scala 中的 lazy val
。
我已经遍历 the docs,但找不到任何东西。只有一章是关于"lazily loading a library",但不是我要的
基于这项研究,我倾向于相信(如果我错了请纠正我)目前没有这样的事情。但也许您知道将提供该功能的任何计划或功能请求?或者它可能被 Dart 团队考虑并拒绝了?
如果确实没有对此的原生支持,那么实现惰性求值的最佳实践(最佳语法)是什么?一个例子将不胜感激。
编辑:
我正在寻找的功能的好处与在其他语言中实现的功能基本相同:Scala's lazy val
or C#'s Lazy<T>
or Hack's __Memorize attribute:
- 语法简洁
- 延迟计算直到需要值
- 缓存结果(按需 懒惰)
- 不要破坏纯函数范式(下面有解释)
一个简单的例子:
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);
}
getter 非常冗长并且有重复的代码。 此外,我不能使构造函数 const
因为缓存变量 _res
必须按需计算。我想如果我有一个类似 Scala 的 lazy
特性,那么我也会有语言支持来拥有一个常量构造函数。这要归功于这样一个事实,即惰性评估 _res
是 referentially transparent, and would not be in the way.
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);
}
更新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());
}
在 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;
}
}
中尝试
原创
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.
}
中尝试
更新
int _val;
int get val => _val ??= 9;
感谢@Nightscape
旧
我认为这个小片段可能会对您有所帮助...
int _val;
int get val => _val ?? _val = 9;
2021 年更新
从 2.12 版开始,延迟初始化现在是 dart 的一部分。
只需在变量声明中添加late
修饰符
late MyClass obj = MyClass();
并且这个对象只有在第一次使用时才会被初始化。
来自docs:
Dart 2.12 添加了 late
修饰符,它有两个用例:
- 声明一个不可为 null 的变量,该变量在其之后初始化
宣言.
- 延迟初始化一个变量。
在此处查看示例:
https://dartpad.dev/?id=50f143391193a2d0b8dc74a5b85e79e3&null_safety=true
class A {
String text = "Hello";
A() {
print("Lazily initialized");
}
sayHello() {
print(text);
}
}
class Runner {
late A a = A();
run() async {
await Future.delayed(Duration(seconds: 3));
a.sayHello();
}
}
这里的class A
只有在使用的时候才会初始化
是否有本地(支持语言)惰性求值语法?类似于 Scala 中的 lazy val
。
我已经遍历 the docs,但找不到任何东西。只有一章是关于"lazily loading a library",但不是我要的
基于这项研究,我倾向于相信(如果我错了请纠正我)目前没有这样的事情。但也许您知道将提供该功能的任何计划或功能请求?或者它可能被 Dart 团队考虑并拒绝了?
如果确实没有对此的原生支持,那么实现惰性求值的最佳实践(最佳语法)是什么?一个例子将不胜感激。
编辑:
我正在寻找的功能的好处与在其他语言中实现的功能基本相同:Scala's lazy val
or C#'s Lazy<T>
or Hack's __Memorize attribute:
- 语法简洁
- 延迟计算直到需要值
- 缓存结果(按需 懒惰)
- 不要破坏纯函数范式(下面有解释)
一个简单的例子:
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);
}
getter 非常冗长并且有重复的代码。 此外,我不能使构造函数 const
因为缓存变量 _res
必须按需计算。我想如果我有一个类似 Scala 的 lazy
特性,那么我也会有语言支持来拥有一个常量构造函数。这要归功于这样一个事实,即惰性评估 _res
是 referentially transparent, and would not be in the way.
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);
}
更新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());
}
在 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;
}
}
中尝试
原创
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.
}
中尝试
更新
int _val;
int get val => _val ??= 9;
感谢@Nightscape
旧
我认为这个小片段可能会对您有所帮助...
int _val;
int get val => _val ?? _val = 9;
2021 年更新
从 2.12 版开始,延迟初始化现在是 dart 的一部分。
只需在变量声明中添加late
修饰符
late MyClass obj = MyClass();
并且这个对象只有在第一次使用时才会被初始化。
来自docs:
Dart 2.12 添加了 late
修饰符,它有两个用例:
- 声明一个不可为 null 的变量,该变量在其之后初始化 宣言.
- 延迟初始化一个变量。
在此处查看示例: https://dartpad.dev/?id=50f143391193a2d0b8dc74a5b85e79e3&null_safety=true
class A {
String text = "Hello";
A() {
print("Lazily initialized");
}
sayHello() {
print(text);
}
}
class Runner {
late A a = A();
run() async {
await Future.delayed(Duration(seconds: 3));
a.sayHello();
}
}
这里的class A
只有在使用的时候才会初始化