前几天在思考,Python和JS都拥抱了类型检查(类型注释),但是Ruby却只能用Sorbet这样的影响性能的类型检查器(Ruby没有官方的类型检查工具,引入静态类型检查的gem反而降低了性能),在搜索中找到了 Crystal 这门语言。
看描述我就惊艳到了:作为一个静态语言,Crystal居然长得这么像Ruby,于是本着不妨玩玩的想法,我进行了Crystal的初试。
# A very basic HTTP server |
简介(翻译自Github README) ¶
目标 ¶
Crystal 是具有以下目标的编程语言:
- 和Ruby相似(但不要求兼容)的语法
- 静态类型检查,但不要求处处指定变量或者方法的类型
- 可以call C代码
- 对编译时进行评估和生成代码,避免boilerplate code.
- 编译成高效的原生代码
为什么? ¶
我们喜欢Ruby写代码的高效率
我们也喜欢C运行代码的高效率
我们想要集二者所长
我们想要编译器能理解我们,而不是我们对编译器指定类型
我们想要完整的面向对象
而且,我们不想为了让代码跑的更快而去写C代码。
下载安装 ¶
请遵循RTFM方法,Read The Fucking Manual
https://crystal-lang.org/install/
语法 ¶
Crystal的语法高度类似于 Ruby,建议先学会Ruby的语法再说Crystal。
这里只提一些比较亮点的东西。
A+B problem,但是自动泛型 ¶
Crystal有自动类型推断的功能。也就是说,大部分情况下类型声明可以直接不写,比如这样
def add(a, b) |
这段代码有些类似于C++这样写
auto add(auto a, auto b) { |
我个人很喜欢 Ruby和Crystal一脉相承的一个想法:程序员的幸福最大化。 Ruby是这样的,程序员只要负责写的爽就行了,而Ruby要考虑的事情就多了(不是)
让我们看看 Rails 信条 中怎么说
早期 Ruby 的极端邪说就是把程序员的幸福度放到第一位。还把追求幸福置于驱动编程语言与生态圈前进的考量之上。
然而 Python 可能对于“用一种方法,最好只有一种方法来完成一件事”而感到自豪,而 Ruby 则喜欢自身表现力与巧妙。Java 是饱受软件工程师的强力推崇,Ruby 则在欢迎工具里就附上了自尽的绳子。Smalltalk 专注于消息传递的纯粹性,Ruby 则累积关键字和臃肿的语法构造。
Ruby 与众不同的原因是看重的事情不一样。这些考量,都是为了满足和追求软件工程师的幸福。这些追求导致了与其他编程语言的辩论,也打开了主流文化对于究竟什么是软件工程师,以及应该如何应对软件工程师的认知。
Ruby 不仅承认,而且从设计上适应和提升软件工程师的感受。不管它们是不足的、奇思妙想的,还是令人喜悦的。Matz 跨越了惊人难度的实践门槛,让机器面有喜色,且富有人性。Ruby 满满是视觉上的错觉,在我们看起来 Ruby 很简单,清晰,也很优美,背后其实是杂技般的错综复杂。这些选择不是没有代价(问问 JRuby 那些试着要对 Ruby 逆向工程的人看看!),这也是为什么,这是很值得赞扬的一件事。
这是对软件开发另一种愿景的致敬,也决定了我对 Ruby 的钟爱。这不止是简单易用,不仅是美学的元素,也不是单一的技术成就。而是一种愿景,是反文化。Ruby 是一个不适应呆板专业软件开发的人,而是专属于爱好之士的乐土。
回到刚刚的 A+B problem。 即使C++有 auto
(更多静态类型语言会要求你写冗长的泛型),我们为什么不能更进一步呢?传入两个参数,把它们加起来。电脑理所应当可以从参数类型推导结果类型。那我为什么还要写呢?
我在意的是我写得爽不爽,而不是它是不是符合哪个RFC的哪一条。所以,你已经是个成熟的编程语言了,该学会揣摩我到底要写什么类型了。我很喜欢。
面向对象,真的 ¶
Ruby和Crystal都是特别面向对象的语言。比绝大多数自称面向对象的语言还要面向对象。
举个例子,Ruby/Crystal支持这样的写法
3.times do |i| |
这是因为哪怕是数字3也被视为一个对象,是Object的子类,可以有自己的methods
所以在Crystal内可以写出这样极其直观的代码
puts 3.seconds # 00:00:03 |
这些也可以传入到 sleep
中作为参数。sleep 3.seconds
即为sleep3秒,所有人一眼就能看懂,再也不用担心什么sleep传入的int
参数到底是毫秒还是秒的问题。
相似的,由于一切皆对象,可以轻松的这样把一个对象转换为JSON:
require "json" |
缺点 ¶
Crystal目前的生态还有问题,vscode插件甚至无法做到优秀的代码补全和类型检查。好在编译时Crystal会报告你的类型错误,呃()
速度测试 ¶
测试代码:欧拉筛素数,数量级1e8
def get_primes(n) |
相同框架改写的代码,Crystal 用时4.4秒,C++用时1.2秒,nodejs用时7.9秒,ruby用时16.5秒,python用时22秒
说明Crystal确实做到了合格的编译语言的性能(虽然还是比C++多了5倍常数)