为 Try[T] 制作了一个方便的日志记录功能,但因为类型系统而卡住了
Making a convenient logging function for Try[T], but got stuck because of the type system
我想知道这是否可以使用 Scala 的类型系统来完成。
基本上,我想创建一个日志记录方法,它接受类型为 Try[T]
的 result
并根据 result
是否为 [=16] 打印出一条略有不同的消息=] 或 Failure
例如,签名可能看起来像
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")
这将输出
size is 13 kb
如果 size
是 Success(x: Int)
,例如 Success(13)
或
error: size is (not available)
如果 size
如果类型 Failure(t: Throwable)
棘手的部分是我们需要能够访问 Try
中的对象以便打印到屏幕(如果它是 Success
,或者打印选定的默认字符串(例如“(不可用)") 如果它是 Failure
作为占位符。此外,它必须使用非常通用的类型 T
或 Any
,范围可以从简单的标量值到 class 的实例等
这个古怪函数的用例是,它将非常方便地以信息丰富的方式记录 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
}
}
这就是我要做的(好吧,如果我不使用隐式将方法添加到 Try
):
def logTry[T](t: Try[T])(f: Try[T] => String) { println(f(t)) }
val size: Try[Integer] = Try(getSizeFromDatabase())
logTry(size) {
case Success(e) => s"size is $e kb"
case Failure(e) => s"error: size is (${e.getMessage}})"
}
编辑:了解您的要求后
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 的信息的地方打印 "not available",这并不那么简单。
另一种选择是创建一个特殊的格式化程序(想想 "size is ${...} 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")
或
size.log(_._2, size => f"size is $size kb", err => f"(not available because $err)")
我想知道这是否可以使用 Scala 的类型系统来完成。
基本上,我想创建一个日志记录方法,它接受类型为 Try[T]
的 result
并根据 result
是否为 [=16] 打印出一条略有不同的消息=] 或 Failure
例如,签名可能看起来像
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")
这将输出
size is 13 kb
如果 size
是 Success(x: Int)
,例如 Success(13)
或
error: size is (not available)
如果 size
如果类型 Failure(t: Throwable)
棘手的部分是我们需要能够访问 Try
中的对象以便打印到屏幕(如果它是 Success
,或者打印选定的默认字符串(例如“(不可用)") 如果它是 Failure
作为占位符。此外,它必须使用非常通用的类型 T
或 Any
,范围可以从简单的标量值到 class 的实例等
这个古怪函数的用例是,它将非常方便地以信息丰富的方式记录 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
}
}
这就是我要做的(好吧,如果我不使用隐式将方法添加到 Try
):
def logTry[T](t: Try[T])(f: Try[T] => String) { println(f(t)) }
val size: Try[Integer] = Try(getSizeFromDatabase())
logTry(size) {
case Success(e) => s"size is $e kb"
case Failure(e) => s"error: size is (${e.getMessage}})"
}
编辑:了解您的要求后
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 的信息的地方打印 "not available",这并不那么简单。
另一种选择是创建一个特殊的格式化程序(想想 "size is ${...} 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")
或
size.log(_._2, size => f"size is $size kb", err => f"(not available because $err)")