Scala 如果出错则抛出异常,如果成功则不返回任何内容的函数方式
我有一个validateSyntax方法,如果语句的语法无效,它会引发异常,但如果语法正确,则不需要返回任何信息Scala 如果出错则抛出异常,如果成功则不返回任何内容的函数方式,scala,exception,functional-programming,Scala,Exception,Functional Programming,我有一个validateSyntax方法,如果语句的语法无效,它会引发异常,但如果语法正确,则不需要返回任何信息 def validateSyntax(statement: String): Unit = { if (! is_valid(statement)) throw new Exception("syntax is not valid") } 然后我从主界面上称之为: val myStatements = List("foo =! bar", "print(foo + bar)")
def validateSyntax(statement: String): Unit = {
if (! is_valid(statement)) throw new Exception("syntax is not valid")
}
然后我从主界面上称之为:
val myStatements = List("foo =! bar", "print(foo + bar)")
myStatements.foreach(stmt => validateSyntax(stmt))
如果其中一条语句无效,我希望我的程序退出并抛出异常
目前,我将validateSyntax的返回类型设置为Unit,但我不确定这是一种功能性的方法
还有更惯用的方法吗?抛出异常不是处理Scala中错误的惯用方法,原因有很多,例如: Scala并没有像Java一样的检查异常概念,Scala透视图中的所有异常都是未检查的,所以编译器不会强迫您处理某些异常,因此更容易出错并忘记处理异常; 被视为副作用的例外情况和它们被视为不纯。这并不意味着它们不好或设计不当,而是意味着它们应该以一种特殊的方式处理,因此可能会使代码更加复杂,而没有任何有意义的理由。长时间的讨论超出了这个问题的范围; 错误应该是一个返回值-如果您想强制客户端处理预期的错误,应该选择适当的结果类型; 因此,在您的情况下,您可以选择下一个可能的选项: 用户可以选择[String,Unit]——左边的实例表示一些错误,右边只表示验证通过的事实。 使用经验证的cats-有关更多详细信息,请参阅官方文档: 使用改进的库和普通验证,提供类型级别的证明,以证明某些实体是有效的。有关更多详细信息,请参见项目页面: 如果使用普通,则解决方案如下所示:
def validateSyntax(statement: String): Either[String, Unit] = {
if (!is_valid(statement)) Left("syntax is not valid") else Right(())
}
val myStatements = List("foo =! bar", "print(foo + bar)")
val validatedStatements = myStatements.map(statement => statement -> validateSyntax(statement))
val allErrors = validatedStatements.collect {
case (statement, Left(error)) => s"Statement: `$statement` is invalid because of $error"
}
if(allErrors.nonEmpty) {
println(s"Statements not valid. All errors:\n - ${allErrors.mkString("\n - ")}")
sys.exit(-1)
}
将生成下一个示例输出:
Statements not valid. All errors:
- Statement: `foo =! bar` is invalid because of syntax is not valid
- Statement: `print(foo + bar)` is invalid because of syntax is not valid
如果您希望生成更精确的错误消息,并通过一条以上的规则验证每条语句,那么前面提到的cats Validated可能是一种选择。请参见下面的实施示例:
import cats.data._
import cats.data.Validated._
import cats.instances.string._
import cats.instances.unit._
import cats.syntax.show._
import cats.syntax.validated._
import cats.syntax.foldable._
type InvalidNec[T] = Invalid[NonEmptyChain[T]]
type ValidatedStatement = (String, ValidatedNec[String, String])
type InvalidStatement = (String, InvalidNec[String])
implicit def listShow[T](implicit show: Show[T]): Show[List[T]] = Show.show(_.map(show.show).mkString("\n"))
implicit val invalidNecShow: Show[InvalidNec[String]] = Show.show(_.e.mkString_("\n - ", "\n - ", ""))
implicit val invalidStatementShow: Show[InvalidStatement] = Show.show {
case (statement, invalid) => show"Statement `$statement` is invalid, because of next errors: $invalid"
}
def validateRule1(statement: String): ValidatedNec[String, Unit] = {
val validCondition: Boolean = false // put validation condition here
if(validCondition) ().validNec else "Statement does not satisfy first rule1".invalidNec
}
def validateRule2(statement: String): ValidatedNec[String, Unit] = {
val validCondition: Boolean = false // put validation condition here
if(validCondition) ().validNec else "Statement does not satisfy first rule2".invalidNec
}
def validateSyntax(statement: String): ValidatedNec[String, String] = {
(validateRule1(statement) combine validateRule2(statement)).map(_ => statement)
}
val myStatements = List("foo =! bar", "print(foo + bar)")
val validatedStatements: List[ValidatedStatement] = myStatements.map(statement => statement -> validateSyntax(statement))
val invalidStatements: List[InvalidStatement] = validatedStatements.collect {
case (statement, invalid: InvalidNec[String]) => statement -> invalid
}
if (invalidStatements.nonEmpty) {
println(show"$invalidStatements")
sys.exit(-1)
}
产生下一个输出结果的示例:
Statement `foo =! bar` is invalid, because of next errors:
- Statement does not satisfy first rule1
- Statement does not satisfy first rule2
Statement `print(foo + bar)` is invalid, because of next errors:
- Statement does not satisfy first rule1
- Statement does not satisfy first rule2
希望这有帮助 抛出异常不是处理Scala中错误的惯用方法,原因有很多,例如: Scala并没有像Java一样的检查异常概念,Scala透视图中的所有异常都是未检查的,所以编译器不会强迫您处理某些异常,因此更容易出错并忘记处理异常; 被视为副作用的例外情况和它们被视为不纯。这并不意味着它们不好或设计不当,而是意味着它们应该以一种特殊的方式处理,因此可能会使代码更加复杂,而没有任何有意义的理由。长时间的讨论超出了这个问题的范围; 错误应该是一个返回值-如果您想强制客户端处理预期的错误,应该选择适当的结果类型; 因此,在您的情况下,您可以选择下一个可能的选项: 用户可以选择[String,Unit]——左边的实例表示一些错误,右边只表示验证通过的事实。 使用经验证的cats-有关更多详细信息,请参阅官方文档: 使用改进的库和普通验证,提供类型级别的证明,以证明某些实体是有效的。有关更多详细信息,请参见项目页面: 如果使用普通,则解决方案如下所示:
def validateSyntax(statement: String): Either[String, Unit] = {
if (!is_valid(statement)) Left("syntax is not valid") else Right(())
}
val myStatements = List("foo =! bar", "print(foo + bar)")
val validatedStatements = myStatements.map(statement => statement -> validateSyntax(statement))
val allErrors = validatedStatements.collect {
case (statement, Left(error)) => s"Statement: `$statement` is invalid because of $error"
}
if(allErrors.nonEmpty) {
println(s"Statements not valid. All errors:\n - ${allErrors.mkString("\n - ")}")
sys.exit(-1)
}
将生成下一个示例输出:
Statements not valid. All errors:
- Statement: `foo =! bar` is invalid because of syntax is not valid
- Statement: `print(foo + bar)` is invalid because of syntax is not valid
如果您希望生成更精确的错误消息,并通过一条以上的规则验证每条语句,那么前面提到的cats Validated可能是一种选择。请参见下面的实施示例:
import cats.data._
import cats.data.Validated._
import cats.instances.string._
import cats.instances.unit._
import cats.syntax.show._
import cats.syntax.validated._
import cats.syntax.foldable._
type InvalidNec[T] = Invalid[NonEmptyChain[T]]
type ValidatedStatement = (String, ValidatedNec[String, String])
type InvalidStatement = (String, InvalidNec[String])
implicit def listShow[T](implicit show: Show[T]): Show[List[T]] = Show.show(_.map(show.show).mkString("\n"))
implicit val invalidNecShow: Show[InvalidNec[String]] = Show.show(_.e.mkString_("\n - ", "\n - ", ""))
implicit val invalidStatementShow: Show[InvalidStatement] = Show.show {
case (statement, invalid) => show"Statement `$statement` is invalid, because of next errors: $invalid"
}
def validateRule1(statement: String): ValidatedNec[String, Unit] = {
val validCondition: Boolean = false // put validation condition here
if(validCondition) ().validNec else "Statement does not satisfy first rule1".invalidNec
}
def validateRule2(statement: String): ValidatedNec[String, Unit] = {
val validCondition: Boolean = false // put validation condition here
if(validCondition) ().validNec else "Statement does not satisfy first rule2".invalidNec
}
def validateSyntax(statement: String): ValidatedNec[String, String] = {
(validateRule1(statement) combine validateRule2(statement)).map(_ => statement)
}
val myStatements = List("foo =! bar", "print(foo + bar)")
val validatedStatements: List[ValidatedStatement] = myStatements.map(statement => statement -> validateSyntax(statement))
val invalidStatements: List[InvalidStatement] = validatedStatements.collect {
case (statement, invalid: InvalidNec[String]) => statement -> invalid
}
if (invalidStatements.nonEmpty) {
println(show"$invalidStatements")
sys.exit(-1)
}
产生下一个输出结果的示例:
Statement `foo =! bar` is invalid, because of next errors:
- Statement does not satisfy first rule1
- Statement does not satisfy first rule2
Statement `print(foo + bar)` is invalid, because of next errors:
- Statement does not satisfy first rule1
- Statement does not satisfy first rule2
希望这有帮助 您可以在左侧使用编码错误,在右侧使用有效结果
您可以在左侧使用编码错误,在右侧使用有效结果
我会这样做:
type Error = String
type Statement = String
type Statements = List[Statement]
type ErrorOr[A] = Either[Error, A]
def validateSyntax(statement: Statement): Option[Error] =
if (is_valid(statement)) None
else Some("syntax is not valid")
def ensureAllAreValid(statements: Statements): ErrorOr[Statements] = {
@annotation.tailrec
def loop(remaining: Statements, acc: Statements): ErrorOr[Statements] =
remaining match {
case statement :: tail =>
validateSyntax(statement) match {
case Some(error) =>
Left(error)
case None =>
loop(
remaining = tail,
statement :: acc
)
}
case Nil =>
// If the order is not important,
// Remove the reverse which is somewhat costly.
Right(acc.reverse)
}
loop(remaining = statements, acc = List.empty)
}
}
def main(): Unit = {
val myStatements = List("foo =! bar", "print(foo + bar)")
ensureAllAreValid(myStatements) match {
case Left(error) =>
println(error)
system.exit(-1)
case Right(statements) =>
???
}
}
我会这样做:
type Error = String
type Statement = String
type Statements = List[Statement]
type ErrorOr[A] = Either[Error, A]
def validateSyntax(statement: Statement): Option[Error] =
if (is_valid(statement)) None
else Some("syntax is not valid")
def ensureAllAreValid(statements: Statements): ErrorOr[Statements] = {
@annotation.tailrec
def loop(remaining: Statements, acc: Statements): ErrorOr[Statements] =
remaining match {
case statement :: tail =>
validateSyntax(statement) match {
case Some(error) =>
Left(error)
case None =>
loop(
remaining = tail,
statement :: acc
)
}
case Nil =>
// If the order is not important,
// Remove the reverse which is somewhat costly.
Right(acc.reverse)
}
loop(remaining = statements, acc = List.empty)
}
}
def main(): Unit = {
val myStatements = List("foo =! bar", "print(foo + bar)")
ensureAllAreValid(myStatements) match {
case Left(error) =>
println(error)
system.exit(-1)
case Right(statements) =>
???
}
}
你能解释一下否决票吗,这样我就不会重蹈覆辙了?我没有否决票。但你可能想检查一下。为了得到好的反馈,你需要展示你的代码。我想我的问题只涉及函数的签名,而不需要知道函数的主体。我用最少的代码编辑了我的问题,说明了我的案例引发异常是一种副作用,因此您的代码不起作用。您可以使用“任意”或“尝试”或“甚至”选项重构此文件,但我们需要了解更多有关您的用例的信息。请参阅以了解您必须在功能上处理此文件的选项之间的所有差异。请您解释否决票,以便我不再重复错误。我没有否决票。但你可能想检查一下。为了得到好的反馈,你需要展示你的代码。我想我的问题只涉及函数的签名,而不需要知道函数的主体。我用最少的代码编辑了我的问题,说明了m
Casey抛出异常是一种副作用,因此您的代码不起作用。您可以使用“或”或“尝试”或“甚至”选项重构此文件,但我们需要更多地了解您的用例。请参阅以了解您必须在功能上处理此文件的选项之间的所有差异。