这次发布一下 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::parseInt("1234"), 1234); assertEquals(Long::parseLong("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 吧,等有时间,再做几个例子传上去。
就这样~~
引用来自“Andyfoo”的评论
这个项目帮了我不少忙,请你吃饭吧,哈哈