在flatmapping AnyRef之后,Scala无法解析正确的重载SLF4J方法*
我有一个如下所示的Java接口:在flatmapping AnyRef之后,Scala无法解析正确的重载SLF4J方法*,scala,slf4j,scala-java-interop,Scala,Slf4j,Scala Java Interop,我有一个如下所示的Java接口: 接口Bazz{ 空栏(字符串消息、对象参数…); } 我想实现该接口(恰好在Scala中),并使用SLF4J日志记录args参数(为了解决这个问题,使用另一个Scala日志库不是一个选项) 以及以下(人为)scala代码: 对象Foo扩展Bazz{ private val log=LoggerFactory.getLogger(Main.getClass) 定义栏(参数:AnyRef*){ info(“处理参数:{},{},{},{}”,参数:*) //…用a
接口Bazz{
空栏(字符串消息、对象参数…);
}
我想实现该接口(恰好在Scala中),并使用SLF4J日志记录args
参数(为了解决这个问题,使用另一个Scala日志库不是一个选项)
以及以下(人为)scala代码:
对象Foo扩展Bazz{
private val log=LoggerFactory.getLogger(Main.getClass)
定义栏(参数:AnyRef*){
info(“处理参数:{},{},{},{}”,参数:*)
//…用args做一些事情。。。
}
}
对象主应用程序{
val arr:Seq[String]=数组(“A”、“B”、“C”)
val anyRef:anyRef=arr
食品酒吧(arr)
}
}
运行Main
,我得到以下输出:
22:49:54.658 [run-main-0] INFO: sample.Main$ Processing params: WrappedArray(A, B, C), {}, {}
这不好,因为:*
正在分解args,但第一个元素是数组。出于不在这里讨论的原因,我实际上需要将该数组的元素作为单个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
[error]Main.scala:18:重载的方法值信息和可选项:
[错误](x$1:org.slf4j.Marker,x$2:String,x$3:[对象])单位
[错误](x$1:org.slf4j.Marker,x$2:String)单位
[错误](x$1:String,x$2:Throwable)单位
[错误](x$1:String,x$2:[对象])单位
[错误](x$1:String,x$2:Any)单位
[错误]无法应用于(字符串,任意)
[error]log.info(“处理参数:{},{},{},{}”,flatArgs:*)
[错误]^
[错误]发现一个错误
如何更改此代码以使其编译并打印
处理参数:A、B、C
?这里的问题是Int
是AnyVal
,这意味着它不是AnyRef/Object
另外,数组
不是可遍历的数组
现在在foo
方法中,我们对varargs进行模式匹配
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
不是集合,它不扩展它)。它可以包含AnyVal
或AnyRef
,但运行时的实际项将被包装为原语(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
可以为空,或包含多个条目。ggovan的更简单变体,在调用foo
之前进行匹配:
val arr: Seq[Int] = Array(1,2,3)
val anyRef: AnyRef = arr
val msg = "Another message: {}, {}, {}"
anyRef match {
case seq: Seq[_] => foo(msg, seq.asInstanceOf[Seq[AnyRef]]: _*)
case x => foo(msg, x)
}
这是我重新陈述(现在很明显)的问题的答案。抱歉之前没有明确的问题:
def条(args:AnyRef*){
val flatArgs=args.flatMap{
案例s:Seq[\u]=>s
案例x=>序号(x)
}.toArray.asInstanceOf[Array[Object]]
info(“处理参数:{},{},{},{}”,flatArgs:*)
}
注意:如果没有[Array[Object]]
的安装,则会发生以下情况:
[error] type mismatch;
[error] found : Array[Any]
[error] required: Array[Object]
[error] Note: Any >: Object, but class Array is invariant in type T.
[error] You may wish to investigate a wildcard type such as `_ >: Object`. (SLS 3.2.10)
[error] }.toArray
[error] ^
[error] one error found
为什么要使用
AnyRef
?修改我的问题以澄清这一点。这是关于java互操作的。听起来可能很糟糕,但您可能能够通过模式匹配参数?也就是说,案例x:WrappedArray[\u]=>东西
我同意@Ven<代码>anyRef:anyRef是这里的问题args
是一个单元素数组,其中第一个元素是WrappedArray
。使用foo(“message”,arr:*)
来获得所需的行为。我一直使用AnyRef*,因为这就是使用VarArgs实现Java接口的方式。抱歉…重新编写了我的问题。请再读一遍。