"Handlebars 的 rust 实现"

本来一度感觉到用过 Clojure 之后很难对新语言产生兴趣了,还好遇到了 Rust 再次激活了这方面的生命力。今年的重点之一是学习 Rust 语言,方便自己能真正 touch bare metal。1月17号的 Rust 聚会上发现很多人都持有类似的想法。 C++ 之后鲜有这种语言,以至于之后成长起来的一代人都是在一个 VM 里编程,无论是 Java 还是 Python,最终都没有办法自己去管理内存,Rust 的出现给了大家一个机会。一个具备现代特性的系统编程语言,Zero runtime,可以运行在各种设备上。去年还给程序员杂志写了一篇 Rust 的文章,结果导致现在程序员杂志停刊了。

扯远了,和当时学 Clojure 一样,这次的计划还是写一个正经的项目来促进学习。关于时机的选择,主要是 crates.io 仓库的发布基本上标志生态圈开始建立了,这个时候写东西就方便很多了。

这次选的就是实现 Handlebars,主要原因是 rust 已经逐渐有一点 web 开发的生态圈了,但是缺少一个模版引擎,于是我就来趟这潭浑水吧。为什么是 Handlebars 呢:

  • 不要把 rust 代码写进 html 模版里,反例: jsp, ejs
  • 不要把 html 代码写进 rust 里,反例: hiccup
  • 能够复用,基于“继承”而不是 include
  • 能够简单地自定义标签,反例:mustach

基于以上的原则,handlebars-rust 实现了基本的模版解析、渲染,重用机制(partial/include)和自定义 helper。除了不支持一些 mustach 风格的语法以外(可以用 #each / #if 这样的 helper 替代,更清晰),基本上所有的 handlebars 功能全部支持了。如果有遗漏的话欢迎 PR。另外还写了一个 handlebars-iron 项目,作为一个 Iron 框架的 middlaware。

简单总结几点收获:

  • Rust 中要实现类似OO的多态需要用枚举类型,trait可以用来做范型
  • 静态类型语言和一个基于 javascript 视角的模版引擎对接很困难,比如 js 里有 falsy 的概念,if 的判断里 false/0/""/[] 这些值都是 false,但是在rust里需要根据不同类型作判断,直接使用简直不可能。所以在 handlebars-rust 里利用了 rustc-serialize 里的 Json 枚举类型(没有真正序列化),要求所有渲染的数据都必须实现 ToJson,算是设计上的一个取舍。
  • Rust 的 derive 是一个神奇的功能,后来发现确实是一个 magic,因为可以 derive 的 trait 都是写死在编译器里的
  • 关于 Rust 的 ownership 看这篇文章,作者承诺再写一篇关于 borrow 和 lifetime 的,相信也不错
  • 有任何问题都可以在 stackoverflow 上问,有几个人会很快回复