我想用元数据注释以非侵入性的方式实现调用缓存(记忆)。
希望它会像这样工作:
class A{
@Cached
foo(msg) {
return msg;
}
}
void main() {
@Cached
var foo = ()=>"hello";
}
可以实现dart:mirrors
吗?
我想用元数据注释以非侵入性的方式实现调用缓存(记忆)。
希望它会像这样工作:
class A{
@Cached
foo(msg) {
return msg;
}
}
void main() {
@Cached
var foo = ()=>"hello";
}
可以实现dart:mirrors
吗?
不久前,我写了一篇关于这个主题的完整博客文章。这里复制太长,所以这里是链接:
http://dartery.blogspot.com/2012/09/memoizing-functions-in-dart.html
结果是您可以编写高阶记忆函数,但由于 Dart 缺乏灵活的 args 函数,它们在一般情况下受到限制。此外,如果您想使用带有递归函数的动态编程,您需要在编写函数时考虑到记忆 - 它需要将自己作为参数,因此您可以传入记忆版本。
我目前的解决方案允许:
class B {
@CachedCallName(#cachedBaz)
baz() => print("first call to baz");
}
class A extends B with CacheableCalls {
@CachedCallName(#foo)
_foo(msg) {
print("first call with: $msg");
return msg + msg;
}
}
void main() {
A a = new A();
print(a.foo(21));
print(a.foo(21));
a.cachedBaz();
print(a.foo(22));
a.cachedBaz();
}
输出:
第一次致电:21
42
42
第一次致电 baz
第一次致电:22
44
缺陷:
- 无法使用实际名称缓存方法。
- 可以扩展集合视图,但不能缓存现有的运算符,例如operator []
- 不能缓存函数。
完整来源:
@MirrorsUsed(metaTargets: CachedCallName)
import 'dart:mirrors';
class CachedCallName {
final Symbol name;
const CachedCallName(this.name);
}
@proxy
class CacheableCalls {
Map _cache = new Map();
dynamic _chacheInvoke(InstanceMirror thisMirror, Symbol
methodName, Invocation invocation) {
String key = "$methodName${invocation.positionalArguments}"
"${invocation.namedArguments}";
if (_cache.containsKey(key)) {
return _cache[key];
} else {
InstanceMirror resultMirror = thisMirror.invoke(methodName,
invocation.positionalArguments, invocation.namedArguments);
_cache[key] = resultMirror.reflectee;
return resultMirror.reflectee;
}
}
dynamic noSuchMethod(Invocation invocation) {
bool isFound = false;
var result;
Symbol called = invocation.memberName;
InstanceMirror instanceMirror = reflect(this);
ClassMirror classMirror = instanceMirror.type;
classMirror.instanceMembers.forEach((Symbol name, MethodMirror mm) {
mm.metadata.forEach((InstanceMirror im) {
if (im.reflectee is CachedCallName) {
if (im.reflectee.name == called) {
isFound = true;
result = _chacheInvoke(instanceMirror, name, invocation);
}
}
});
});
if (isFound) {
return result;
} else {
throw new NoSuchMethodError(this, called,
invocation.positionalArguments, invocation.namedArguments);
}
}
}
class B {
@CachedCallName(#cachedBaz)
baz() => print("first call to baz");
}
class A extends B with CacheableCalls {
@CachedCallName(#foo)
_foo(msg) {
print("first call with: $msg");
return msg + msg;
}
}
void main() {
A a = new A();
print(a.foo(21));
print(a.foo(21));
a.cachedBaz();
print(a.foo(22));
a.cachedBaz();
}