crystal简介

574 阅读2分钟
原文链接: zhenfeng-zhu.github.io

关注crystal也有一段时间了,看到多线程的pr已经提了,今天简单写一下。

Fast as C, Slick as Ruby

语法

crystal的语法和Ruby比较类似。

# A very basic HTTP server
require "http/server"

server = HTTP::Server.new do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world, got #{context.request.path}!"
end

puts "Listening on http://127.0.0.1:8080"
server.listen(8080)

类型系统

crystal的一大卖点就是静态类型系统,但是写起来又和脚本语言类似。

def shout(x)
# Notice that both Int32 and String respond_to `to_s`
x.to_s.upcase
end

foo = ENV["FOO"]? || 10

typeof(foo) # => (Int32 | String)
typeof(shout(foo)) # => String

空引用检查

crystal可以在编译的时候检查空引用,避免出现空指针异常。

if rand(2) > 0
my_string = "hello world"
end

puts my_string.upcase

如果运行上述的代码,执行结果如下:

$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))

puts my_string.upcase

另一个重要的特性是宏。通过宏,可以实现向ruby那么强大的元编程。

class Object
def has_instance_var?(name) : Bool
{{ @type.instance_vars.map &.name.stringify }}.includes? name
end
end

person = Person.new "John", 30
person.has_instance_var?("name") #=> true
person.has_instance_var?("birthday") #=> false

并发

crystal的并发是通过绿色线程实现的,即fibers。和Go的并发模式很像,也是基于channel的CSP模型。

channel = Channel(Int32).new
total_lines = 0
files = Dir.glob("*.txt")

files.each do |f|
spawn do
lines = File.read(f).lines.size
channel.send lines
end
end

files.size.times do
total_lines += channel.receive
end

puts total_lines

C绑定

C语言一般用来实现比较底层的系统,而且C的生态丰富,一般现代语言都会提供C绑定,来复用C的生态。

# Fragment of the BigInt implementation that uses GMP
@[Link("gmp")]
lib LibGMP
alias Int = LibC::Int
alias ULong = LibC::ULong

struct MPZ
_mp_alloc : Int32
_mp_size : Int32
_mp_d : ULong*
end

fun init_set_str = __gmpz_init_set_str(rop : MPZ*, str : UInt8*, base : Int) : Int
fun cmp = __gmpz_cmp(op1 : MPZ*, op2 : MPZ*) : Int
end

struct BigInt < Int
def initialize(str : String, base = 10)
err = LibGMP.init_set_str(out @mpz, str, base)
raise ArgumentError.new("invalid BigInt: #{str}") if err == -1
end

def <=>(other : BigInt)
LibGMP.cmp(mpz, other)
end
end

依赖管理

任何一个偏工程性的语言,都会提供一个包管理系统。crystal的包管理是shards,其实和go module类似。这种项目级别的包管理其实更为实用一些。

但是go的任何一个项目,其实都可以是一个包,crystal还是会有一些限制的。

name: my-project
version: 0.1
license: MIT

crystal: 0.21.0

dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.3.1