scala类型系统的输入验证
现在我已经玩了一点Scala,我问自己应该如何在Scala中进行输入验证 这是我多次看到的:scala类型系统的输入验证,scala,validation,types,implicit-conversion,Scala,Validation,Types,Implicit Conversion,现在我已经玩了一点Scala,我问自己应该如何在Scala中进行输入验证 这是我多次看到的: def doSomethingWithPositiveIntegers(i: Int) = { require(i>0) //do something } 要想让事情变得更清楚,感觉就像在Java中这样做: void doSomething(Object o) { if (!o instanceof Integer) throw new IllegalAr
def doSomethingWithPositiveIntegers(i: Int) = {
require(i>0)
//do something
}
要想让事情变得更清楚,感觉就像在Java中这样做:
void doSomething(Object o) {
if (!o instanceof Integer)
throw new IllegalArgumentException();
}
在那里,你首先接受比你愿意接受的更多的东西,然后引入一些只让“好的”进来的“守卫”。确切地说,在每个处理正整数的函数中都需要这些保护,如果您希望稍后包含零,则需要更改每个函数。当然,您可以将它转移到另一个函数,但是您始终需要记住调用正确的函数,并且它可能无法通过类型重构等。听起来我不希望这样。我正在考虑将此验证代码推送到数据类型本身,如下所示:
import scala.util.Try
object MyStuff {
implicit class PositiveInt(val value: Int) {
require(value>0)
}
implicit def positiveInt2Int(positiveInt: PositiveInt): Int = positiveInt.value
}
import MyStuff._
val i: MyStuff.PositiveInt = 5
val j: Int = i+5
println(i) //Main$$anon$1$MyStuff$PositiveInt@3a16cef5
println(j) //10
val sum = i + i
println(sum) //10
def addOne(i: MyStuff.PositiveInt) = i + 1
println(Try(addOne(-5))) //Failure(java.lang.IllegalArgumentException: requirement failed)
println(Try(addOne(5))) //Success(6)
然后我有一个类型PositiveInt
,它只能包含正整数,我可以(几乎)像Int
一样在任何地方使用它。现在,我的API定义了我愿意接受的内容——这就是我想要的!函数本身没有什么需要验证的,因为它知道它只能得到有效的正整数——没有验证就无法构造它们。您只需在创建类型时运行一次验证!想想其他情况,验证可能更昂贵(验证电子邮件地址或URL,或者验证数字是否为素数)
优点:
do(String,String,String)
可以是do(用户、电子邮件、密码)
)def makeNegative(i: PositiveInt): NegativeInt = -i
addOne(makeNegative(1)) //will create a compile-time error!
val i: PositiveInteger = 5
val range = i to 10 //error: value to is not a member of this.MyStuff.PositiveInt
val range = i.value to 10 //will work
如果您可以扩展Int
并只添加require
,则可以解决此问题,因为所有PositiveInt
都是Int
s(实际情况是这样!),但Int
是final:)。您可以为所有需要的情况添加隐式转换,但这将非常冗长PositiveInt
隐式转换为RichInt
)您可以使用工厂方法创建一个私有构造函数对伴随对象可见的类,例如
class PositiveInt private[PositiveInt](val i: Int)
object PositiveInt {
def apply(i: Int): Option[PositiveInt] = if(i > 0) Some(new PositiveInt(i)) else None
}
客户机无法直接创建
PositiveInt
的实例,因此他们必须通过apply
方法进行验证,并且只在输入值有效时返回有效实例。是的,但是-我想实现的是,用户不需要知道存在验证。在这种情况下,我需要显式实例化PositiveInt
实例-我不能简单地用(positive)Int
实例调用需要PositiveInt
的函数。但这正是我想做的……如果您想要不应用或fromInt
或类似内容,则返回选项的应用方法是不直观的。