Добавление журнала, если возвращаемое значение нет
-
26-10-2019 - |
Вопрос
Предположим, есть две функции findUser(id:String):Option[User]
а также findAddress(user:User):Option[Address]
вызывается следующим образом:
for(user <- findUser(id); address <- findAddress(user)) println(address)
Теперь я хотел бы добавить в это журнал ошибок в это for-comprehension
. Анкет Я хотел бы назвать log(msg:String)
функционируйте, если user
или же address
не найден.
for(user <- findUser(id) ifNone log("user not found"); address <- findAddress(user) ifNone log("address not found")) println(address)
Могу ли я сделать это, не изменяя функциональные подписи?
Решение
Может быть
implicit def withIfNone[A](o: Option[A]) = new {
def ifNone(action: => Unit) = { if (o == None) action; o }
}
Вы также можете рассмотреть возможность использования любого вместо опции (или преобразования ваших параметров или либо). Это не сработает с фореатом (для без урожая), но вы можете сделать
for(
a <- option1.toRight("option1 missing").right;
b <- option2.toRight("option2 missing").right)
yield f(a,b)
Тогда вы можете соответствовать рисунку в результате с
case Left(error) => log (error)
case Right(result) => // use result
Другие советы
Лифт Box
это более подходящий класс для вашего случая использования. А Box
как Option
, но с двумя пустыми состояниями: ОК и ошибкой. Вы можете использовать это так:
val addr = for {
user <- findUser(id) ?~ "user not found"
address <- findAddress(user) ?~ "address not found"
} yield address
address match {
case Full(addr) => println(addr)
case oops: Failure => println(oops.msg) // see Failure for more details
}
Видеть этот блог для различных предложений, связанных с вашей проблемой.
Это может быть излишним, но это похоже на то, что вы хотели;)
object Extensions {
// You need a wrapper since Option is sealed
class OptionWrapper[E](option: Option[E]) {
def foreach[U](f: E => U) {
option foreach f
}
def isEmpty = option.isEmpty
}
// Modification trait for OptionWrapper
trait ErrorLogging[E] extends OptionWrapper[E] {
abstract override def foreach[U](f: E => U) {
if (isEmpty)
println("error")
else
super.foreach(f)
}
}
// Accessor for the new mixin
def log[E](option: Option[E]) = new OptionWrapper(option) with ErrorLogging[E]
}
object TestingLogger extends App {
case class User(address: String)
def findUser(id: Int): Option[User] = if (id == 1) Some(User("address")) else None
def findAddress(user: User): Option[String] = Some(user.address)
import Extensions._
for {
user <- log(findUser(1)) // prints out address
address <- log(findAddress(user))
} println(address)
for {
user <- log(findUser(2)) // prints out error
address <- log(findAddress(user))
} println(address)
}
Если вы понятия не имеете, что только что произошло это.