8

自从开始使用 Dart 以来,我一直在寻找一种将 Dart(文本)源(同一程序很可能动态生成)作为代码执行的方法。就像臭名昭著的“eval()”函数。

最近我发现了一些提示,即 Isolates 之间的通信端口支持某种“Spawn”,似乎它可以允许这种“技巧”。在 Ruby 中,也可以将模块作为语言特性动态加载,也许在 Dart 中有一些方法可以做到这一点?

任何线索或一个简单的例子将不胜感激。

提前致谢!

4

4 回答 4

13

Ladislav Thon 提供了这个答案(在 Dart 论坛上),

我相信可以肯定地说 Dart 永远不会有 eval。但它会有其他更结构化的动态生成代码的方式(代号镜像构建器)。不过,现在没有这样的事情。

有两种方法可以生成隔离:spawnFunction,它从新隔离中的现有代码运行现有函数,所以你不需要寻找任何东西,以及 spawnUri,它从给定的 URI 下载代码并在新隔离中运行它。这本质上是动态代码加载——但动态加载的代码与现有代码是隔离的。它在一个新的隔离中运行,因此与它通信的唯一方式是通过消息传递(通过端口)。

谢谢拉迪斯拉夫...

于 2012-11-27T13:24:14.937 回答
8

您可以将字符串作为 Dart 代码运行,方法是首先从中构造一个数据 URI,然后将其传递到Isolate.spawnUri.

import 'dart:isolate';

void main() async {
  final uri = Uri.dataFromString(
    '''
    void main() {
      print("Hellooooooo from the other side!");
    }
    ''',
    mimeType: 'application/dart',
  );
  await Isolate.spawnUri(uri, [], null);
}

请注意,您只能在 JIT 模式下执行此操作,这意味着您可能会从中受益的唯一地方是 Dart VM 命令行应用程序/包:构建脚本。它不适用于 Flutter 发布版本。

要从中获取结果,您可以使用ports

import 'dart:isolate';

void main() async {
  final name = 'Eval Knievel';
  final uri = Uri.dataFromString(
    '''
    import "dart:isolate";

    void main(_, SendPort port) {
      port.send("Nice to meet you, $name!");
    }
    ''',
    mimeType: 'application/dart',
  );

  final port = ReceivePort();
  await Isolate.spawnUri(uri, [], port.sendPort);

  final String response = await port.first;    
  print(response);
}

我在我的博客上写过它

于 2019-08-15T07:39:25.477 回答
1

至少在 Ruby 中,Eval() 可以执行从单个语句(如赋值)到完成相关程序的任何内容。与大多数其他可能的执行形式相比,执行许多小片段会花费大量时间。

仔细研究这个问题,至少有三个不同的函数是可以使用 eval 的各种方案的基础。Dart 至少以最少的方式处理其中的 2 个。

Dart 没有,看起来也没有计划支持“通用”脚本执行。

但是,可以使用 NoSuchMethod 方法有效地将变量动态“注入”到本地类环境中。它将 eval() 替换为如下所示的字符串: eval("String text = 'your first name here';" );

Dart 现在支持的第二个函数是调用方法,它看起来像这样: eval("Map map = SomeClass.some_method()" );

在搞砸了这个之后,我终于明白,一个简单的类可以用来存储调用方法所需的信息,对于一个类,作为一个似乎具有通用实用性的字符串。我可以替换一个易于维护的大型 switch 语句,否则它可能需要调用一系列方法。在 Ruby 中,这几乎是微不足道的,但是在 Dart 中,有一些相当不直观的调用,所以我想在一个地方获得这个“技巧”,它适合对字符串进行排序和过滤,例如您可能需要的。

这是使用反射将尽可能多的类(整个库?)“累积”到映射中的代码,这样 class.methodName() 只需一个键(作为字符串)就可以调用。

注意:我使用了一些“辅助方法”来执行 Map & List 功能,您可能想用直接 Dart 替换它们。但是,此代码仅使用函数进行使用和测试..

这是代码:

//The used "Helpers" here..
MAP_add(var map, var key, var value){ if(key != null){map[key] = value;}return(map);}
Object MAP_fetch(var map, var key, [var dflt = null]) {var value = map[key];if (value==null) {value = dflt;}return( value );}


class ClassMethodMapper {
  Map    _helperMirrorsMap, _methodMap;

  void accum_class_map(Object myClass){
    InstanceMirror helperMirror = reflect(myClass);
    List methodsAr  = helperMirror.type.methods.values;
    String classNm  = myClass.toString().split("'")[1]; ///#FRAGILE      
    MAP_add(_helperMirrorsMap, classNm, helperMirror);
    methodsAr.forEach(( method) {
      String key = method.simpleName;
      if (key.charCodeAt(0) != 95) { //Ignore private methods
        MAP_add(_methodMap, "${classNm}.${key}()", method);
      }
    });
  }

  Map invoker( String methodNm ) {
    var method = MAP_fetch(_methodMap, methodNm, null);
    if (method != null) {         
      String classNm = methodNm.split('.')[0];        
      InstanceMirror helperMirror = MAP_fetch(_helperMirrorsMap, classNm);
      helperMirror.invoke(method.simpleName, []);
    }
  }

  ClassMethodMapper() {
    _methodMap         = {};
    _helperMirrorsMap  = {};
  }
}//END_OF_CLASS( ClassMethodMapper );


============

main() {
   ClassMethodMapper cMM = new ClassMethodMapper();
   cMM.accum_class_map(MyFirstExampleClass);
   cMM.accum_class_map(MySecondExampleClass);

   //Now you're ready to execute any method (not private as per a special line of code above)
   //by simply doing this:
   cMM.invoker( MyFirstExampleClass.my_example_method() );
}
于 2013-01-10T10:00:29.813 回答
0

实际上pub.dev/packages中有一些库,但由于是年轻版本,所以有一些限制,所以我可以向你推荐这个库表达式来飞镖和颤振。

解析和评估简单表达式的库。

这个库可以处理简单的表达式,但不能处理代码块、控制流语句等。它支持大多数编程语言通用的语法。

在那里,我创建了一个代码示例来评估算术运算和数据比较。

import 'package:expressions/expressions.dart';
import 'dart:math';

@override
Widget build(BuildContext context) {
 final parsing = FormulaMath();
 // Expression example
 String condition = "(cos(x)*cos(x)+sin(x)*sin(x)==1) && respuesta_texto == 'si'";

 Expression expression = Expression.parse(condition);

 var context = {
   "x": pi / 5,
   "cos": cos,
   "sin": sin,
   "respuesta_texto" : 'si'
 };

 // Evaluate expression
 final evaluator = const ExpressionEvaluator();
 var r = evaluator.eval(expression, context);
 print(r);


 return Scaffold(
   body: Container(
     margin: EdgeInsets.only(top: 50.0),
     child: Column(
       children: [
         Text(condition),
         Text(r.toString())
       ],
     ),
   ),
 );
}

我/颤振(27188):真

于 2021-09-29T20:11:50.660 回答