1

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
  end
end

daisy = Person.new "Daisy Johnson"
chappie = Person.new 22

puts daisy.inspect
puts 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" : 42
if a.is_a? String
  # 这里 a 的类型是 String
  puts a.size
else
  # 这里 a 的类型是 Int32
  puts a / 2
end

Nil 的处理

在静态类型语言中, 有的编译器默认允许 nil/null, 那么就会抛出 NPE (NullPointerException), 有的编译器会在类型上禁止一些 nil/null 的存在, 并鼓励用 Maybe/Option 去装箱/拆箱. 前一种方法很容易出错, 后一种方法使用繁琐 (尤其在不支持 do notation 的语言中). 而 Crystal 结合数据流分析, 对 nil 值的处理更加简单优雅. 文档里的例子如下:

a = some_condition ? nil : 3
# a is Int32 or Nil

if a
  # Since the only way to get here is if a is truthy,
  # a can't be nil. So here a is Int32.
  a.abs
end

不过为了线程安全, 非局部变量不推荐这么做

if @a
  @a.abs # 如果编译器分析出 @a 可以赋值 nil, 就会出编译错误
end

上面的代码可以加锁, 或者改写成局部变量判断的方式

if a = @a
  a.abs # 别的线程就改不了局部变量啦
end

和 Ruby 一样, 由于 Nil 上可以定义方法, 所有值都自然变成 Maybe Monad 了, 上面的代码也可以改成用 try 去处理

@a.try do |a|
  a.abs
end

在 responds_to 的情形, 会出现这类代码 pattern

if (a = @a).responds_to? :size
  a.size
end

不那么静态

从上面可以看到, 和一般的静态语言相比, Crystal 的一个局部变量的类型并不是固定的

a = 32 # 现在 a 的类型是 Int32
a.abs
a = "foo" # 现在 a 的类型是 String
a.length

在 while 循环中, 编译器会做更复杂的事情, 尽量不让类型成为阻碍编程的限制, 以下例子出自 Crystal 博客:

a = 1
while 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 Bool
end
a               # here a is Int32 or String or Bool

来自知乎
http://www.zhihu.com/question/33311554
--- (未完待续)


天赢金创
338 声望21 粉丝

天赢金创,天赢金创,天赢金创,天赢金创,天赢金创,天赢金创天赢金创,天赢金创


引用和评论

0 条评论