原标题:西行漫记之Haxe初探·上篇

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

1. 简述:haxe是啥?

haxe(读作蛤克思),是以前flash时代诞生的一种的开源跨平台方案。学会了haxe,可以直接用这种类似TypeScript的语法,生成对应的js/php/python/c++等源码,亦可以直接通过脚本编译成指定target(比如exe

 

1.1 历史背景

Haxe往前,是flash的ActionScript3.0,AS3之前是AS2。AS3用的是ES4的语法,现在的JavaScript,用的是ES6的语法。如果没记错的话,AS2的语法属于JavaScript1.5魔改。

ActionScript3是Adobe出于性能考虑,用了JVM做的实现。相比较,现行的Node.js用的是Chrome的V8。

 

1.2 Haxe跟TypeScript的区别

其实不太想写这段的,但是还是为了方便,顺手科普一下。TS是JS的超集,HX是AS3的变种,有亲属关系。需要注意的是,Haxe3的语法,相比ES6其实已经落后了,但这并不影响日常使用,因为haxe的生态还是足够stable的。

 

1.1.1 什么人还在用Haxe?

主要还是这几类:Flash遗老、一部分大龄游戏开发者、以及一部分需要跨平台的游戏开发者。具体可以参考官网的介绍。

 

1.0 相关的链接

所有本文涉及到的主要参考链接我都先摆在前面,因为这样方便自己检索。

官网:https://haxe.org 答疑聊天室:https://gitter.im/HaxeFoundation/haxe 

在线测试hx代码:https://try.haxe.org   API参考:https://api.haxe.org

手册:https://haxe.org/manual/introduction.html  库索引:https://lib.haxe.org

关于宏的参考/1:https://jcward.com/A+Beginners+Guide+To+Hacking+Haxe+Macros

lime命令行:http://lime.software/docs/command-line-tools/basic-commands/

openfl文档:http://www.openfl.org/learn/

以上,暂时就这些。另外,答疑聊天室里面有不少香港的,而且懂的还挺多。

 

2. hello world

说来惭愧,用haxe写一个hello world其实挺复杂的。

2.1 准备工作

首先你需要安装haxeToolkit,然后,你需要一个编辑器,这里我选vscode。安装完haxe之后,在vscode里面顺便安装haxe的插件。

2.2 hello world的本体

1 class Main {
2     static function main() {
3         trace("Hello, World!");
4     }
5 }

标准的写法,其实要在main函数前面加一个public。然后把代码写入Main.hx里面,是的,和java一样,haxe也要就文件名同类名保持一致/且类名必须大写开头。而且,Haxe3.4目前,还不支持标识符[identifier]用中文,据说4.0会实现,但我觉得,也不是非常有必要,毕竟还可以用拼音。

2.3 如何运行

这是整个hello world的关键。官方教程[x1]给的用法是通过haxe命令行:

 haxe -main Main --interp

 这里补充一点,-main参数实际上的意思是,指定提供main函数的class/file。--interp是解释执行的意思,haxeToolkit里面有自带一个虚拟机叫neko(关于这个细节,一开始不用太在意,知道neko是对标lua的轻量级VM就好)。

2.3.1 如何生成exe / 命令行方法

haxe -main Main -cpp build

第一次编译需要点时间。另外应该是需要msbuild的cl或者mingw的gcc来编译的,不过因为自己本机已经有vs2017的build tool了,所以没有另外单独测试过编译环境的依赖问题。编译完成后,命令行运行build\Main.exe即可看到调试输出的结果。

https://haxe.org/manual/target-cpp.html

2.3.2 生成exe的标准策略

标准策略是:用hxml把编译参数单独写出来,然后用 haxe build.hxml 指定到对应hxml即可。

https://haxe.org/manual/compiler-usage-hxml.html

2.3.3 除了转成cpp然后生成exe还有那些输出方式?

个人觉得除了cpp,其他算是常用的还有两种:输出js、输出成neko/然后用nekoVM执行。python的话,倾向于在haxe里面调用python,而不是生成py代码。php和java个人很少能用到,不过也算常见方案。

 

3. hello world之后该干嘛

这时候你有很多选择,首先取决于你想干嘛。

 Haxe:东游记(上)part1:intro 随笔

上图为haxe之上的架构。通常来说,haxe+openfl的关系,很接近C# + WPF。个人觉得haxe还是适合做替代js的活多一点,当然,这方面TypeScript明显更有优势,只是haxe比TS用途更多一点而已。

 

3.1 我打算用Haxe干嘛

首先是满足日常需求。比如以前拿python写爬虫,今后就换成haxe来做。类似的,也可以替代部分typescript。当然最后还是想在haxe里面直接调用erlang/elixir,以及kdb+/q。其次是用来填坑,当然,小程序用haxe来做,也不是不可以,但是准备工作似乎有点多,不如直接用typescript+taro。其他的坑,erlang这边可以试着用haxe来调用,在一个就是用haxe来实现一个适合编程的输入法。

 

3.2 我能在haxe方面做哪些有意义的事情

首先是Haxe的中文化。这里的中文化,不是说要汉化Haxe的代码/语法/文档等等,而是根据需要,补充相关的中文使用参考。比如变量命名,我想在haxe的代码内形成一个自己的用词规范,方便以后用来做输入法测试。

 

4. 写这篇的时候踩了哪些坑?

首先是文档的坑。haxe的API文档,只能搜索class,而不能搜索到class下的function。这时候最好借助第三方搜索工具。比如最开始hello world里面的trace()函数,实际上是在haxe.Log底下的。

其次是宏的使用问题。我写java少,所以看到public static function的时候,很想做个简化,看能否写成psf。后来折腾了一圈下来发现,除非改AST,别无他法。所以最后放弃了,为了偷个小懒而去改AST,没必要。

再次是,因为想重定义现有的库函数名,所以需要用macro做一些预处理工作,于是写了这么一个helper:

import haxe.macro.Expr;
class Util{
  public static macro 
function yin(e:Array<Expr>){ return macro trace($a{e}); } }

这里的import Expr,不严格要求可以不写。另外还顺便试了一下在class里面写import,不行,只能写class外面。关于macro的用法,主要参考:https://haxe.org/manual/macro-reification-expression.html  。 这里的$a{}的a,是Array的意思,yin是印的拼音。

最后是,因为macro默认是static function,在继承的时候发现,class的static函数不会被继承。这个我去gitter问了一下,说就目前是这么设计的(估计是考虑到inline到其他target需要优化的缘故)。然后有个德国大佬说,你可以用macro实现这个feature[x2]。我想了想,还是用以前,python pyramid的ZCA架构下的traversal套路比较简单。于是写了一个回溯/类函数的helper-> tryStatic:

 1 public static function 
tryStatic(c,field){
2 var gsc=Type.getSuperClass; 3 var gcf=Type.getClassFields; 4 var rf = Reflect.field; 5 var L=[c]; var Lflag=-1; 6 7 while (Lflag!=1){ 8 var d = L[L.length-1]; 9 if(d==null) return
rf(L[L.length-2],field); 10 else L.push(gsc(d)); 11 var d2 = gcf(d); 12 var Lflag = d2.indexOf(field); 13 } 14 return rf(L[L.length-1],field); 15 }

这个代码发到gitter上的时候,有个香港的dalao说,你这个第2/3/4行的var定义有点多余,会影响inline,进而会影响性能。这个倒是提醒了我,因为这个玩法虽然在py里面没事,但是在cpp里面有没有影响,我还真说不好。不过测试了一下两种不同的策略,生成的js代码实际差不多(感觉不影响js性能)。在一个就是他有提到可读性的问题,说我这个rf()可读性不如原先的。我说这个是用APL用习惯了,代码/变量名越短越好,英文可读性是次要的(有逻辑可读性就行)。

 

1.3 为什么选择了haxe?

首先,TypeScript没法用很简洁的办法生成stand alone的exe文件,这不适合我用来教学。其次,haxe的语法虽然有点过时,但是基本够用,有些甚至比TS好。比如pattern matching,TS为了兼容ES标准,没有做标准的模式匹配语法,只做了destructure[1][2]。

其次,Haxe的历史包袱小,依赖少,很轻量,用途广。可以说,自己已经打算逐步用haxe代替python了。

 

5. 下次写点什么?

主要写haxe中文化的基本思路,其他视情况做补充。

 

尾注:

[2] typescript下的模式匹配:https://pattern-matching-with-typescript.alabor.me

[x2] https://github.com/maitag/peote-view-remaster/blob/master/src/peote/view/Element.hx#L215

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄