这次发布一下 2.1.0-beta, 依然是个 beta 版本, 原因参考这里: https://www.oschina.net/news/85315/febit-wit-2-0-0-beta. <dependency> <groupId>org.febit.wit</groupId> <artifactId>wit-core</artifactId> <version>2.1.0-beta</version> </dependency> 本次更新带来一个新语法: 函数引用操作符 :: 和 Java8 中新增的函数引用操作符是同一个概念, `Math::max` `String::valueOf` 这样, 就得到了一个函数的引用, 不仅仅是静态函数, 构造函数也可以 `StringBuilder::new`, 成员函数也可以 `String::length`, 还可以带包名 `java.util.List::size`,当然 如果 `@import java.util.List;` 之后可以简写成 `List::size`. 那么怎么吃? 可以清蒸, 可以凉拌... 哦不, 可以直接调用 `Math::max(x, y)`, 也可以赋值到变量后再用 `var func = String::length; echo func("hi");` 当然啦, 必须是 `public` 的方法才可以! 和 `native` 有啥区别? 当前的 native 一个函数引用, 是需要指定参数类型的, 例如: `var func = native String::valueOf(Integer)` 使用这个从操作符就不需要了, 当存在不用参数类型的重载时, 会根据传入的参数类型选择一个 "比较合适的" 函数来调用 (恩, 到底选比较复杂, 目前是根据转换权重来算的, 想了解的可以看一下源代码) 性能方面, 对于控制欲比较强的小伙伴,也可以考虑 native 和那个 `.~` 操作符有啥区别? `.~` 是一个比较 freestyle 的存在, 类型&函数 都是运行时才去取的, 以 `obj.~size()` 为例, 运行的时候根据 `obj` 的类型取名为 `size` 的函数, 是 List 是 Map 只要有名为 size 的 public 的成员函数就可以, 如果有不同参数类型的重载, 同样会根据实际的传参适配一个 '::' 就比较中规中矩了, 指定了哪个类型, 编译成语法书的时候就从那个类型上提前找出有哪些同名的函数, 理论上性能比较好, 但是如果是成员方法, 第一个参数必须是实例本身, 用起来就很麻烦: `Map::size(map)`, 而 `map.~size()` 就比较简单 差不多了, 来看几个例子吧: { @import org.febit.wit.util.StringUtil; var max = Math::max; assertEquals(max(1,2), 2); assertEquals(Math::max(1,2), 2); assertEquals(Math::min(1,2), 1); assertEquals(String::length("1234"), 4); assertEquals(String::valueOf("1234"), "1234"); assertEquals(String::valueOf(1234), "1234"); assertEquals(Integer:arseInt("1234"), 1234); assertEquals(Long:arseLong("1234"), 1234L); assertEquals(StringUtil::format("[0]={}, [1]={}, [2]:{}", ["aaaa", "bbb", 2]), "[0]=aaaa, [1]=bbb, [2]:2"); } { var new_stringbuilder = native new StringBuilder(); var buf = new_stringbuilder(); buf.~append("123").~append(456); assertEquals("123456", buf.~toString()); assertEquals("123456", StringBuilder::toString(buf)); } { var buf = StringBuilder::new(); StringBuilder::append(StringBuilder::append(buf, "123"), "233"); assertEquals("123233", StringBuilder::toString(buf)); buf = StringBuilder::new("233"); assertEquals("233", buf.~toString()); buf = StringBuilder::new(123); assertEquals(123, buf.~capacity()); } 好了, 有同学就问了, "现在前后端都分离了, 你做这个破东西有啥用?" papapa, 敲黑板! 对于前后端分离, 我是双手赞成! 实际上在做这个模板引擎之前, 作为青涩的全栈小码农, 就已经在实践前后端分离了. 那时候, 只是只是为了偷懒, 做了个代码生成器 (https://github.com/febit/febit-generator), 迭代了几个版本, 用了各种模板引擎, 后来跟人拌了几句嘴, 决定自己做个模板引擎. 那么, 除了做代码生成器, 还能用来做什么? 渲染一些必须在后端渲染的邮件什么的 当脚本引擎来用, 执行一些动态脚本, 你看, 只有 330kB 大小, 嵌到系统根本没压力嘛 当规则引擎来用, 取出持久化的每个字段的表达式, 拼成脚本然后执行得到结果 放个例子出来: https://github.com/febit/wit-toys 感兴趣的话, 关注一下: https://github.com/febit 吧, 等有时间, 再做几个例子传上去. 就这样~~ Wit 2.1.0-beta 发布,Java 模板引擎(原 Webit Script)下载地址