我希望以非侵入方式使用元数据注释实现调用缓存(memoization)。
希望它会像这样工作:
class A{
@Cached
foo(msg) {
return msg;
}
}
void main() {
@Cached
var foo = ()=>"hello";
}
只能使用dart:mirrors
吗?
答案 0 :(得分:4)
我刚才写了一篇关于这个主题的博客文章。复制到这里太长了,所以这里有链接:
http://dartery.blogspot.com/2012/09/memoizing-functions-in-dart.html
结果是你可以编写更高阶的记忆功能,但是由于Dart缺乏灵活的args功能,它们的普遍性受到限制。另外,如果你想使用带有递归函数的动态编程,你需要记住你的memoization函数 - 它需要将自己作为一个参数,所以你可以传入memoized版本。
答案 1 :(得分:0)
我目前的解决方案允许:
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个
第一次打电话给巴兹 第一次打电话: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();
}