Dart中的“Expando”特性是什么,它有什么作用?

33

最近在Dart中看到了“Expando”这个术语,听起来很有趣。但API并没有给我提供太多线索。

提供一个或两个示例可能会更有帮助!

(不确定是否相关,但我最渴望的是一种添加方法(访问器)和/或变量到类中的方法。希望这可能是解决这个问题的关键。(提示: 我现在正在使用Nosuchmethod方法,并希望能够返回未找到的方法的值。))

提前感谢,

_swarmii

3个回答

24

为了澄清expando和maps之间的区别:正如在groups中所报道的,expando具有弱引用
这意味着即使一个键仍然存在于expando中(只要没有其他引用),它也可能被垃圾回收。

对于所有其他目的,它是一个map。


21

扩展允许您将对象与其他对象关联起来。这种方法非常有用,例如对于HTML DOM元素,因为它本身无法被子类化。 让我们创建一个顶级扩展程序,以添加一些功能到一个元素中-在这种情况下是在typedef语句中给出的函数签名:

typedef CustomFunction(int foo, String bar);

Expando<CustomFunction> domFunctionExpando = new Expando<CustomFunction>();

现在来使用它:

main(){
   // Assumes dart:html is imported
   final myElement = new DivElement();

   // Use the expando on our DOM element.
   domFunctionExpando[myElement] = someFunc;

   // Now that we've "attached" the function to our object,
   // we can call it like so:
   domFunctionExpando[myElement](42, 'expandos are cool');
}

void someFunc(int foo, String bar){
  print('Hello. $foo $bar');
}

16
这个和 Map<Element, CustomFunction> 有什么不同? - Zdeněk Mlčoch
3
Expando无法防止键被垃圾回收!在这方面,它可以与JavaScript的WeakMap进行比较。 - Marvin H.

1

我稍微试用了一下,这是我得到的结果。

import 'dart:html';

const String cHidden = 'hidden';

class ExpandoElement {
  static final Expando<ExpandoElement> expando =
      new Expando<ExpandoElement>("ExpandoElement.expando");

  final Element element;

  const ExpandoElement._expand(this.element);

  static Element expand(Element element) {
    if (expando[element] == null)
      expando[element] = new ExpandoElement._expand(element);
    return element;
  }

//  bool get hidden => element.hidden; // commented out to test noSuchMethod()
  void set hidden(bool hidden) {
    if (element.hidden = hidden)
      element.classes.add(cHidden);
    else
      element.classes.remove(cHidden);
  }

  noSuchMethod(InvocationMirror invocation) => invocation.invokeOn(element);
}
final Expando<ExpandoElement> x = ExpandoElement.expando;
Element xquery(String selector) => ExpandoElement.expand(query(selector));

final Element input = xquery('#input');

void main() {
  input.classes.remove(cHidden);
  assert(!input.classes.contains(cHidden));

  input.hidden = true;
  assert(x[input].hidden); // Dart Editor warning here, but it's still true
  assert(!input.classes.contains(cHidden)); // no effect

  input.hidden = false;
  assert(!x[input].hidden); // same warning, but we'll get input.hidden via noSuchMethod()
  assert(!input.classes.contains(cHidden));

  x[input].hidden = true;
  assert(input.hidden); // set by the setter of ExpandoElement.hidden
  assert(input.classes.contains(cHidden)); // added by the setter
  assert(x[input].hidden);
  assert(x[input].classes.contains(cHidden)); // this is input.classes

  x[input].hidden = false;
  assert(!input.hidden); // set by the setter
  assert(!input.classes.contains(cHidden)); // removed by the setter
  assert(!x[input].hidden);
  assert(!x[input].classes.contains(cHidden));

  // confused?
  assert(input is Element);
  assert(x[input] is! Element); // is not
  assert(x[input] is ExpandoElement);
  assert(x is Expando<ExpandoElement>);
}

在我发布这篇文章的当天,Dart版本是r19425。 - Ladios Jonquil
如果 (element.hidden = hidden) <-- 不确定,但这看起来非常可疑,能详细说明一下吗? - Mattias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接