【天赢金创】Crystal 语言
Beautiful Syntax, Faster Than Go
它和 Mirah, JRuby, Groovy 等等的区别是: 它不需要 JVM 这个平台, 没有字节码和解释器. 很容易在速度上超过这些 JVM 语言.
同样是编译成 LLVM IR 再到机器码, 和 Ruby Motion 的区别是: Ruby Motion 依赖 ObjC 运行时, 而 Crystal 不依赖
除了编译外, 和 Elixir 的区别还有: 它的语法和 Ruby 很相似, 所以 Crystal 编译器可以直接用 Crystal 和 Ruby 的交集写, 然后用 Ruby 执行编译自己, 就轻松完成了 bootstrap. 它的语法对熟悉 Ruby 的人更有亲和力, 所以 Matz 率先捐了 $500.
所以你看, 虽然现在还在 Alpha 阶段, 还是很有存在意义的.
Crystal 还有一些与众不同的特性:
面向对象类型推导
在一些静态类型系统上结合 FP 和面向对象的尝试中, 例如 Scala 中, 推导仅局限于方法内部. 而 Crystal 没有这个限制, 它会尽量修改类型定义以满足使用需要
举个栗子:
class Person getter name def initialize @name endenddaisy = Person.new "Daisy Johnson"chappie = Person.new 22puts daisy.inspectputs chappie.inspect
使用 hierarchy 命令查看类图
$ crystal hierarchy person.cr...+- class Person (24 bytes) | @name : (String | Int32) (16 bytes)...
可以看到 Person 的 name 属性的类型自动变成了 String | Int32
if 表达式类型推导
和 Ruby 一样, Crystal 的 if 语句有返回值, 是表达式. 但 if 表达式在很多静态语言中的使用却不那么便利, 一个巨大问题就是编译器不能根据条件去做推断, 例如:
val a = if (args.length > 0) { "string" } else { 42 } // a 的类型是 Any
if (a.isInstanceOf[String]) {
println(a.length) // 编译错误, Any.length 没定义, 得手动强转
}
而 Crystal 的类型推断会考虑条件中的 is_a? 和 responds_to? 信息, 减少了繁琐的强制转换:
a = ARGV.size > 0 ? "string" : 42if a.is_a? String # 这里 a 的类型是 String puts a.sizeelse # 这里 a 的类型是 Int32 puts a / 2end
Nil 的处理
在静态类型语言中, 有的编译器默认允许 nil/null, 那么就会抛出 NPE (NullPointerException), 有的编译器会在类型上禁止一些 nil/null 的存在, 并鼓励用 Maybe/Option 去装箱/拆箱. 前一种方法很容易出错, 后一种方法使用繁琐 (尤其在不支持 do notation 的语言中). 而 Crystal 结合数据流分析, 对 nil 值的处理更加简单优雅. 文档里的例子如下:
a = some_condition ? nil : 3# a is Int32 or Nilif a # Since the only way to get here is if a is truthy, # a can't be nil. So here a is Int32. a.absend
不过为了线程安全, 非局部变量不推荐这么做
if @a @a.abs # 如果编译器分析出 @a 可以赋值 nil, 就会出编译错误end
上面的代码可以加锁, 或者改写成局部变量判断的方式
if a = @a a.abs # 别的线程就改不了局部变量啦end
和 Ruby 一样, 由于 Nil 上可以定义方法, 所有值都自然变成 Maybe Monad 了, 上面的代码也可以改成用 try 去处理
@a.try do |a| a.absend
在 responds_to 的情形, 会出现这类代码 pattern
if (a = @a).responds_to? :size a.sizeend
不那么静态
从上面可以看到, 和一般的静态语言相比, Crystal 的一个局部变量的类型并不是固定的
a = 32 # 现在 a 的类型是 Int32a.absa = "foo" # 现在 a 的类型是 Stringa.length
在 while 循环中, 编译器会做更复杂的事情, 尽量不让类型成为阻碍编程的限制, 以下例子出自 Crystal 博客:
a = 1while some_condition a # here a is Int32 or String or Bool if some_other_condition a = "hello" # we next, so in the next iteration a can be String next end a = false # here a is Boolenda # here a is Int32 or String or Bool
来自知乎
http://www.zhihu.com/question/33311554
--- (未完待续)