Scala 为Try[T]创建一个方便的日志记录功能,但由于类型系统而被卡住
我想知道是否可以使用Scala的类型系统来实现这一点 基本上,我想创建一个日志记录方法,它接受类型为Try[T]的Scala 为Try[T]创建一个方便的日志记录功能,但由于类型系统而被卡住,scala,casting,type-conversion,scala-generics,Scala,Casting,Type Conversion,Scala Generics,我想知道是否可以使用Scala的类型系统来实现这一点 基本上,我想创建一个日志记录方法,它接受类型为Try[T]的结果,并根据结果是成功还是失败打印出一条稍有不同的消息 例如,签名可能看起来像 def logTry[T](what: Try[T], block: T => String): Unit 并且可以这样使用: val size: Try[(Int, Int)] = Try(getSizeAndTimestampFromDatabase()) logTry(size, e =&g
结果,并根据结果是成功还是失败打印出一条稍有不同的消息
例如,签名可能看起来像
def logTry[T](what: Try[T], block: T => String): Unit
并且可以这样使用:
val size: Try[(Int, Int)] = Try(getSizeAndTimestampFromDatabase())
logTry(size, e => "size is " + e._2 + " kb")
哪个会输出
大小为13KB
如果大小
为Success(x:Int)
,例如Success(13)
或
错误:大小为(不可用)
ifsize
if类型Failure(t:Throwable)
棘手的部分是,如果成功
,我们需要能够访问Try
中的对象以打印到屏幕上;如果失败
,我们需要打印所选的默认字符串(例如“(不可用)”),作为占位符。此外,它还必须使用非常通用的类型T
或Any
,其范围从简单的标量值到类的实例等
这个古怪函数的用例是,它将非常方便地以信息性的方式记录Try对象,而不会使代码与map/recover或match语句混淆
这是我想出来的骨架,当然最难的部分还没有弄清楚
def logTry[T](what: Try[T], block: T => String): Unit = {
what match {
case Success(res) => println(block(res))
case Failure(t) => println(???) // how to do this
}
}
这就是我要做的(如果我没有使用implicits将方法添加到Try
):
编辑:在理解您的请求之后
def logTry(t: Try[Any], f: Any => String) {
t match {
case Success(e) => println(f(e))
case Failure(e) => println(f(new Object {
override def toString = "(not available)"
}))
}
}
val size: Try[Integer] = Try(getSizeFromDatabase())
logTry(size, s => s"Size is $s kb")
我不知道如何实现泛型类型t,但我认为这无论如何都不是一个好主意:客户机在打印时可以特别使用t的方法,但您希望它总是在应该打印来自t的信息的地方打印“不可用”,这并不是那么简单
另一个选项是创建一个特殊的格式化程序(想想“大小是${…}kb”
),这样记录器就会知道如何替换它,但我不确定这是否是您想要的。这里是解决方案,它不会强制您显式提供类型:
implicit class LogTry[T](attempt: Try[T]) {
def log[E](comp: T => E, block: String => String, error: Throwable => String = _ => "(N/A)") =
println(block(attempt map (comp andThen (_.toString)) recover { case ex => error(ex) } get))
}
把它当作
size.log(_._2, size => f"size is $size kb")
或
如果我们这样做,我们将强制函数的用户显式地处理成功和失败案例。此外,如果要避免重复,则必须将错误/成功消息写入两次,或者将其声明为单独的val。在my函数中,当值不可用时,我们提供一个合理的占位符。您提供了什么占位符?我懂了???处理一个错误。如果您只是想打印“error”,为什么不在原始实现中这样做呢?仅供参考,?
是Predef
中的有效方法???是“throw new NotImplementedError”的别名,我将其解释为“我不知道在这里做什么”。如果你想从外部接收字符串,你可以按照我下面@Odomontois的建议去做。我把它放在那里,因为我正在研究如何实现这个部分。我想要的输出应该是size是13kb
或error:size是(不可用)kb
。这不够简洁,想象一下如果我们可以这样做logTry[(Int,Int)](size,e=>f“size是${e.\u 2}kb”)
并得到一个非常合理的输出,即size是(N/a)kb
-不可用值将自动替换为“占位符”
size.log(_._2, size => f"size is $size kb")
size.log(_._2, size => f"size is $size kb", err => f"(not available because $err)")