【问题标题】:Is there a compiler preprocessor in Dart?Dart 中有编译器预处理器吗?
【发布时间】:2013-12-15 18:46:58
【问题描述】:

由于在启动 dart 应用程序之前需要进行编译,我想知道编译器预处理器是否可用,或者是否计划在不久的将来用于 Dart。
到目前为止,我在网络/飞镖网站内的搜索已被证明是不成功的。

(通过预处理器,我的意思是:

#define max(A,B)    ( (A) > (B) ? (A):(B)) 

或:

#define NumType double
#define NumTypeZero 0.0

// used with :
NumType myNum = NumTypeZero;

或:

#define DEBUG 

// use
#ifdef DEBUG
   print('var1 : $var1, var2:$var2, ...');
#endif

)

编辑:我想知道为什么还没有预处理器,因为从那时起我们似乎已经“接近”了:
- Dart 必须扫描文件以查找库依赖项,才能以正确的顺序加载库。
- Dart 编辑器还扫描文件以进行语法、类型检查和其他检查。
- 可以在编辑器中启动一些自动文件处理(我找不到有价值的链接,如果有,请告诉我)。

【问题讨论】:

    标签: compilation dart


    【解决方案1】:

    基本上是其他人说的......

    如果您使用 dart2js 进行编译,如果 DEBUG 是一个常量且为 false,那么摇树将已经抛出 if (DEBUG) {} 块内的代码。所以你可以只使用 if 语句。

    您也可以使用 assert() 语句。使用 dart2js 编译生产模式时,断言和传递给它的表达式将被丢弃。

    所以这实际上与您使用 #ifdefs 得到的行为相同 - 您可以将 dart2js 视为您的预处理器;)

    我也看不出有什么理由要使用#defines 而不是常量。

    如果你想在 DartVM 中运行你的代码,你可以使用 dart2js --output-type=dart 在你的 dart 源上做 tree-shaking。

    更新:另请参阅 String.fromEnvironment()bool.fromEnvironment()int.fromEnvironment()。您可以在编译时使用“dart2js -D=”设置这些环境变量。

    【讨论】:

    【解决方案2】:

    目前还没有 Dart 的预处理器。我也不相信在不久的将来会计划这样做。见Issue 7238

    Dart 不需要编译。仅生成可供 Dart VM 之外的应用程序使用的 Javascript。例如服务器端 Dart 脚本从不需要编译。它们可以生成快照以减少加载时间,但这需要更少的编译步骤,更多的是在应用程序启动后存储 VM 的状态。

    也就是说,已经有很多关于依赖注入或其他基于环境的依赖管理系统的讨论,但目前尚未达成共识或决定。见Issue 76

    编辑:

    1) 我对在加载库时使用“正确顺序”一词犹豫不决。对于 Dart VM 本身,它本质上是在加载脚本时加载所有库符号,然后开始执行代码并将符号与表中的符号进行匹配。 dart2js 编译器做了类似的事情,但也会实现 treeshaking 以 try 以隔离未使用的代码并将其从最终编译中省略。但我远非 VM 或 JavaScript 编译器大师,无法获得有关该过程如何完成的更多信息。

    2) 与其他解释语言类似,许多/大多数检查是在运行时执行的,而不是编译时步骤。事实上,Dart VM 设计为在禁用类型检查的情况下运行。它仅用于开发,实际上会对执行速度造成重大影响。

    3) 我相信您指的是 build.dart 文件。你可以在Build.dart and the Dart Editor找到更多信息

    另请注意,Dart 编辑器实际上正在运行一个名为 dart_analyzer 的 dart 脚本,以在您键入时验证代码。它正在改进,但仍远非完美。它执行了许多步骤来尝试假设并将类型和值与代码相关联,但它还必须符合 dart 语言规范。因此,即使分析器能够根据周围代码假设类型,它仍然必须提供警告,例如类型 Node 没有与之关联的 getter“值”,即使分析器知道传递的 Node 实际上是一个文本输入字段。

    【讨论】:

      【解决方案3】:

      来自http://blog.sethladd.com/2013/12/compile-time-dead-code-elimination-with.html

      假设你有这样的代码:

      log(String msg) {
        if (const String.fromEnvironment('DEBUG') != null) {
          print('debug: $msg');
        }
      }
      
      main() {
        log('In production, I do not exist');
      }
      

      使用dart2js -DDEBUG=true app.dart 编译时,输出包括日志记录行为:

        main: function() {
          H.printString("debug: In the production release, I do not exist");
        }
      

      (日志函数被内联,但打印仍然发生)

      但是,如果未设置 -DDEBUG,则生成的 JavaScript 代码中不包含日志记录行为:

        main: function() {
        }
      

      【讨论】:

      • 您能否确认 .fromEnvironment() 方法也允许以同样的方式忽略代码?它将允许与#DEFINE 预处理器字完全相同的功能。
      【解决方案4】:

      不,没有,我怀疑会有。

      对于您的第一个示例,相当于定义 最大(a,b)=> a > b?一:乙;

      或者,更简单地说 导入“飞镖:数学”;

      已经包含了。

      第二个等价物是 NumType 的 typedef,但现在 Dart typedefs 仅适用于函数类型。更通用的 typedef 似乎可能会出现在以后的版本中。对于 0.0 部分,只需 常量 numTypeZero = 0.0;

      目前没有等效于 ifdef 的条件代码执行。但是,如果您在程序开始时定义 常量调试 = 假; 并写道 if (DEBUG) print("stuff");

      这将大致完成您想要的。

      您正在寻找的东西都是 C 习语,通常用于性能。 Dart 的编译器非常聪明,不需要其中的一些。

      因此,例如,以这种方式定义 max 可能是为了强制它被内联。如果 Dart 认为值得,它会自行内联它,并且有能力在执行过程中改变主意。将某些东西声明为“const”使其成为编译时常量,因此与#define 的效果几乎相同。通过定义像 DEBUG 这样的符号来减少代码大小的能力是 Dart 现在缺少的,尽管条件编译可能比大小更重要。如果您在浏览器中运行,并且编译器在浏览器中,那么减少代码大小的关键在于下载。如果你等到编译器运行,那就太晚了,你已经下载了代码。如果你提前编译成 JS,它会省略 if 语句中由常量 false 限定的代码。还有一个 dart2dart 模式可以进行这些转换,以及缩小 Dart 源代码。但在有本地​​运行 Dart 的浏览器之前,这并不重要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-16
        • 1970-01-01
        • 1970-01-01
        • 2020-10-12
        相关资源
        最近更新 更多