gpt4 book ai didi

在平面映射 AnyRef* 后,Scala 无法解析正确的重载 SLF4J 方法

转载 作者:行者123 更新时间:2023-12-02 00:39:45 25 4
gpt4 key购买 nike

我有一个如下所示的 Java 接口(interface):

interface Bazz {
void bar(String msg, Object args...);
}

我想实现该接口(interface)(恰好在 Scala 中)并使用 SLF4J 日志记录 args 参数(对于这个问题,使用另一个 Scala 日志库不是一个选项) .

以及以下(人为的)scala 代码:

object Foo extends Bazz {

private val log = LoggerFactory.getLogger(Main.getClass)

def bar(args: AnyRef*) {
log.info("Processing params: {}, {}, {}", args: _*)
// ... do stuff with args...
}
}

object Main extends App {

val arr: Seq[String] = Array("A","B","C")
val anyRef: AnyRef = arr

Foo.bar(arr)

}

}

运行Main,我得到以下输出:

22:49:54.658 [run-main-0] INFO: sample.Main$ Processing params: WrappedArray(A, B, C), {}, {} 

这不好,因为 :_* 正在爆炸参数,但第一个元素是一个数组。由于我不会在这里讨论的原因,我实际上需要将该数组的元素作为单个 Object[] 参数传递给 SLF4J 的 Logger.info(String, Object[]) 方法。

这是我的第一次尝试:

def bar(args: AnyRef*) {
val flatArgs = args.flatMap {
case s: Seq[_] => s
case x => Seq(x)
}
log.info("Processing params: {}, {}, {}", flatArgs: _*)
// ... do stuff with args...
}

编译时不会出现以下错误:

[error] Main.scala:18: overloaded method value info with alternatives:
[error] (x$1: org.slf4j.Marker,x$2: String,x$3: <repeated...>[Object])Unit <and>
[error] (x$1: org.slf4j.Marker,x$2: String)Unit <and>
[error] (x$1: String,x$2: Throwable)Unit <and>
[error] (x$1: String,x$2: <repeated...>[Object])Unit <and>
[error] (x$1: String,x$2: Any)Unit
[error] cannot be applied to (String, Any)
[error] log.info("Processing params: {}, {}, {}", flatArgs: _*)
[error] ^
[error] one error found

如何更改此代码以使其编译并打印处理参数:A、B、C

最佳答案

这里的一个问题是 IntAnyVal 这意味着它不是 AnyRef/Object另外,Array 不是 TraversableOnce

现在,在 foo 方法中,我们对可变参数进行模式匹配。

def foo(msg:String,varargs:AnyRef*) { varargs.toList match {
case (h:TraversableOnce[_]) :: Nil => log.info(msg, h.toSeq.asInstanceOf[Seq[AnyRef]]:_*)
case (h:Array[_]) :: Nil => log.info(msg, h.toSeq.asInstanceOf[Seq[AnyRef]]:_*)
case _ => log.info(msg,varargs:_*)
}}

我们处理的案例有3种:

case (h:TraversableOnce[_]) :: Nil => log.info(msg, h.toSeq.asInstanceOf[Seq[AnyRef]]:_*)

TraversableOnce 是 Scala 集合的基本特征之一;我知道的每个集合都扩展了它(Array 不是一个集合,它不会扩展它)。它可以包含 AnyValAnyRef,但运行时的实际项目将被包装为基元(java.lang.Integer 等)。因此,我们可以在这里从 Seq[Any] 向下转换为 Seq[AnyRef] ,应该没问题。

case (h:Array[_]) :: Nil => log.info(msg, h.toSeq.asInstanceOf[Seq[AnyRef]]:_*)

就像我们对 TraversableOnce 所做的那样,将其转换为 Seq,然后向下转型。转换为 Seq 将为我们包装所有原语。

case _ => log.info(msg,varargs:_*)

一般情况下,varargs 可能为空,或包含多个条目。

关于在平面映射 AnyRef* 后,Scala 无法解析正确的重载 SLF4J 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24155196/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com