实现依赖于不纯 code/libraries 的纯函数式 Scala 代码时的最佳实践和方法
Best Practices and Approaches while implementing pure functional Scala code which is dependent on impure code/libraries
我目前正在实现依赖于自定义 Scala 库的业务逻辑代码,它有很多不纯的函数,我们有很多代码依赖于这个库,不能重构,因为它会影响其他人。所以我正在尝试尽可能纯粹地编写我的 scala 代码,并且需要一些用例的建议。
我有一个执行以下操作的 LDAP 实用程序库
根据用户名和密码以及returns布尔值进行认证,但是如果出现Connection异常或者找不到用户则直接抛出异常。
基于 UUID 和参数(如名字和姓氏)读取和更新数据的作用几乎相同
我的身份验证用例方法如下
def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
Some(ldapService.authenticate(username,password))
// or using either type to get the message as well
def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
(ldapService.authenticate(username,password)) match {
case true => Right(true)
case false => Left("Validation failed, Invalid Password")
case exception: Exception => Left(exception.toString)
}
//##for Some type
authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))
//##for Either type
// Looking into how to implement
所以我想编写尽可能接近纯函数的函数式代码,需要有关如何处理此类场景以编写函数式 Scala 代码的帮助和建议。
正如 Tim 所说,在 Scala 中处理错误时,最简单的做法是将异常抛出代码包装在 Try 块中。例如:
import scala.util.{Try, Success, Failure}
Try {
connector.makeCall()
} match {
case Success(value) if value => Right("yay")
case Success(value) => Left("☹️")
case Failure(ex) => Left("An exception was thrown")
}
这将 return 如果 connector.makeCall()
行 returns true
为右,如果该行 returns false
则为左或异常。
这是一个人为的例子,但这是您使用它的一种方式 - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q
实际上,提供的代码不能是纯的,因为结果是
authenticateToUpdate
不仅取决于其参数(用户名、密码),还取决于 ldapService
服务。
话虽如此,我建议 authenticateToUpdate
的定义如下:
def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
Try(ldapService(userName, password)) match {
case Success(value) if value => Right("OK")
case Success(_) => Right("Failed to authenticate")
caseFailure(ex) => Left(s"Something wrong: ${ex}")
}
}
authenticateToUpdate("user", "password"){ case (user, password) =>
ldapService.authenticate(username,password)
}
在提供的示例中,我们只是用一个纯函数包装了一个不纯函数。
我目前正在实现依赖于自定义 Scala 库的业务逻辑代码,它有很多不纯的函数,我们有很多代码依赖于这个库,不能重构,因为它会影响其他人。所以我正在尝试尽可能纯粹地编写我的 scala 代码,并且需要一些用例的建议。
我有一个执行以下操作的 LDAP 实用程序库 根据用户名和密码以及returns布尔值进行认证,但是如果出现Connection异常或者找不到用户则直接抛出异常。 基于 UUID 和参数(如名字和姓氏)读取和更新数据的作用几乎相同 我的身份验证用例方法如下
def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
Some(ldapService.authenticate(username,password))
// or using either type to get the message as well
def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
(ldapService.authenticate(username,password)) match {
case true => Right(true)
case false => Left("Validation failed, Invalid Password")
case exception: Exception => Left(exception.toString)
}
//##for Some type
authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))
//##for Either type
// Looking into how to implement
所以我想编写尽可能接近纯函数的函数式代码,需要有关如何处理此类场景以编写函数式 Scala 代码的帮助和建议。
正如 Tim 所说,在 Scala 中处理错误时,最简单的做法是将异常抛出代码包装在 Try 块中。例如:
import scala.util.{Try, Success, Failure}
Try {
connector.makeCall()
} match {
case Success(value) if value => Right("yay")
case Success(value) => Left("☹️")
case Failure(ex) => Left("An exception was thrown")
}
这将 return 如果 connector.makeCall()
行 returns true
为右,如果该行 returns false
则为左或异常。
这是一个人为的例子,但这是您使用它的一种方式 - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q
实际上,提供的代码不能是纯的,因为结果是
authenticateToUpdate
不仅取决于其参数(用户名、密码),还取决于 ldapService
服务。
话虽如此,我建议 authenticateToUpdate
的定义如下:
def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
Try(ldapService(userName, password)) match {
case Success(value) if value => Right("OK")
case Success(_) => Right("Failed to authenticate")
caseFailure(ex) => Left(s"Something wrong: ${ex}")
}
}
authenticateToUpdate("user", "password"){ case (user, password) =>
ldapService.authenticate(username,password)
}
在提供的示例中,我们只是用一个纯函数包装了一个不纯函数。