强动态类型
Ruby使用强动态类型。为了更好的理解这个概念,看例子:
text = "hello world" + 10
运行上面的语句,Ruby解释器会抛出如下错误:
no implicit conversion of Integer into String (TypeError)
可以看到,Ruby中的type设置还不错,不会像Javascript中可以让不同类型的变量混在一起,很容易造成意想不到的结果。
惯例
在使用ROR(Ruby on Rails)框架的时候,遵循惯“例优于配置”的原则(convention over configuraiton)。也就是,大家在编写程序的时候,会遵循Ruby/Rails社区内一些不成文的惯例,如:
def even?(number)
number % 2 == 0
end
上述例子反应了2个惯例:
- 方法名末尾有问号(?)表示这个方法会返回boolean。其实可以命名这个方法为is_even,但是Ruby程序员并不会这么命名。
- 参数名使用number,隐式的表示这个方法的参数是个数字类型。参数可以是任何名称,不过,按照惯例,最好是有意义的并能够反应参数类型的名字。
Sorbet
动态类型语言的弊端在于,当项目规模变大后,会在类型的理解上花费大量的时间。举例子:
class PaymentService
def process(order)
...
return receipt
end
end
上述代码看似直观,但是对于新加入团队的人来说,会问出如下问题:
- order的类型是什么?
- receipt类型是什么?
- 如何知道process方法是返回结果的?
尤其当项目中包含了2种类型的order的时候,Customer::Order和History::Order,究竟应该给process方法传递哪个类型?
Stripe的Dev productivity team推出Sorbet - 面向Ruby的静态类型检查工具。
# typed: true
class PaymentService
extend T::Sig
sig {params(order: Customer::Order).returns(History::Receipt)}
def process(order)
...
return receipt
end
end
上述代码在原有基础上,引入了Sorbet。通过sig 那一行,我们可以明确的知道process方法返回History::Receipt类型的结果,同时,它需要Customer::Order类型的参数。
可以查看Stripe的slides、video了解Stripe内部对Sorbet的反馈(总体是正向的)