在我看来,我可以使用隐式转换来宣布和强制执行前置条件.考虑一下:
object NonNegativeDouble {
implicit def int2nnd(d : Double) : NonNegativeDouble = new NonNegativeDouble(d)
implicit def nnd2int(d : NonNegativeDouble) : Double = d.v
def sqrt(n : NonNegativeDouble) : NonNegativeDouble = scala.math.sqrt(n)
}
class NonNegativeDouble(val v : Double ) {
if (v < 0) {
throw new IllegalArgumentException("negative value")
}
}
object Test {
def t1 = {
val d : Double = NonNegativeDouble.sqrt(3.0);
printf("%f\n", d);
val n : Double = NonNegativeDouble.sqrt(-3.0);
}
}
Run Code Online (Sandbox Code Playgroud)
暂时忽略示例的实际空白:我的观点是,子类NonNegativeDouble表达了一个函数只占用了类的整个范围的子集的概念.
首先是:
其次,这对于基本类型(如Int和String)最有用.当然,这些类是最终的,所以有一种很好的方法不仅可以在函数中使用受限类型(这是第二个隐含的类型),而且还可以委托基础值上的所有方法(缺少手动实现每个委托) )?
这是一个非常酷的想法,但不幸的是它的真正潜力无法在Scala的类型系统中实现.你真正想要的是依赖类型,它允许你在你的方法的调用者上强加一个证明义务,以验证参数是否在范围内,这样甚至不能用无效的参数调用该方法.
但是,如果没有依赖类型和在编译时验证规范的能力,我认为这具有可疑价值,即使不考虑性能考虑因素.考虑一下,如何使用require函数来声明方法所需的初始条件,如下所示:
def foo(i:Int) = {
require (i >= 0)
i * 9 + 4
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,负值都会导致在运行时抛出异常,无论是在require函数中还是在构造函数时NonNegativeDouble.这两种技术都清楚地说明了方法的契约,但我认为构建所有这些特殊类型的开销很大,其唯一目的是封装在运行时声明的特定表达式.例如,如果您想强制执行稍微不同的前提条件,该怎么办?说,那个i > 45?你会IntGreaterThan45为那个方法构建一个类型吗?
我可以看到用于构建例如NonNegativeFoo类型的唯一参数是,如果您有许多方法仅消耗和返回正数.即便如此,我认为收益是可疑的.
| 归档时间: |
|
| 查看次数: |
769 次 |
| 最近记录: |