我是Scala的新手 - 在使用Apache POI生成Excel文件时,我尝试通过此通用删除代码中的重复:
def addCell[A](
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: A)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
不幸的是,编译器报告:
[error] .../mycode.scala:32: overloaded method value setCellValue \
with alternatives:
[error] (x$1: Boolean)Unit <and>
[error] (x$1: String)Unit <and>
[error] (x$1: org.apache.poi.ss.usermodel.RichTextString)Unit <and>
[error] (x$1: java.util.Calendar)Unit <and>
[error] (x$1: java.util.Date)Unit <and>
[error] (x$1: Double)Unit
[error] cannot be applied to (A)
[error] row.createCell(idxColumn).setCellValue(data)
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
我无法得到它 - 无论谁调用addCell
,都会传递特定类型A
(第三个参数的类型data
),因此通用形式应该是能够发送到setCellValue
的正确重载形式。
我可能遗漏了一些明显的东西 - 任何最感谢的帮助。
编辑:为了说清楚 - 我的代码目前正在执行此操作:
field match {
case i:Int => row.createCell(idxCol).setCellValue(i)
case l:Long => row.createCell(idxCol).setCellValue(l)
case f:Float => row.createCell(idxCol).setCellValue(f)
case d:Double => row.createCell(idxCol).setCellValue(d)
case s:String => row.createCell(idxCol).setCellValue(s)
...
我希望通过对
之类的通用调用来避免明显的重复field match {
case i:Int => setCell(row, idxCol, i)
case l:Long => setCell(row, idxCol, l)
case f:Float => setCell(row, idxCol, f)
...
有可能吗?
答案 0 :(得分:4)
最直接的方法是为每种类型编写一个单独的方法:
def addCell(
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: Boolean)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
def addCell(
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: String)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
如果只需要addCell这样写就可以了。
如果您需要更多方法的代码,您可以考虑采用更高级的方法来限制每种方法的样板。
更高级方法的草图:
定义一个cellSetter trait,它可以为单元格设置给定类型的值。
trait CellSetter[A]{
def setCell(cell: Cell, data: A): Unit
}
为所有相关类型实施CellSetter,例如:
implicit val stringCellSetter = new CellSetter[String](){
def setCell(cell: Cell, data: String){
cell.setCellValue(data)
}
}
制作一些糖:
implicit class RichCell(cell: Cell){
def setCellValue[A](data: A)(implicit cellSetter: CellSetter[A]) = cellSetter.setCell(cell, data)
}
为addCell创建一些不错的通用代码:
def addCell[A: CellSetter](
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: A)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
答案 1 :(得分:1)
不是说我做过这样的事情,但我很好奇专业化是否有帮助。
最低限度,你想避免装箱原语。
事实证明,专业化并没有多大帮助,因为专门的方法不会派遣到非专业的方法。我想我以前读过这个问题。
在下文中,专门化add
可以正常工作。一个版本使用ClassTag
选择引用类型,或另一个版本处理基元。但是注释掉的代码只调用了setCellValue(Any)
;布尔版本调用setCellValue(Boolean)
。
评论的版本似乎会破坏后端......
import scala.reflect.ClassTag
import java.util.Date
trait Setter {
def setCellValue(b: Boolean) = println("bool")
def setCellValue(s: String) = println("str")
def setCellValue(n: Double) = println("double")
def setCellValue(d: Date) = println("date")
}
object Test extends App {
def add[@specialized(Boolean, Double) A <: AnyVal](s: Setter, a: A) = {
/*
class ASetter extends Setter {
override def setCellValue(b: Boolean) = s setCellValue b
override def setCellValue(n: Double) = s setCellValue n
def setCellValue(x: Any) = ???
}
(new ASetter) setCellValue a
*/
a match {
case b: Boolean => s setCellValue b
case d: Double => s setCellValue d
case _ => ???
}
}
def add[A: ClassTag](s: Setter, a: A) = a match {
//case _: Boolean | _: Double => s setCellValue a
case d: Date => s setCellValue d
case x: String => s setCellValue x
case _ => ???
}
val s = new Setter {}
add(s, new Date)
add(s, true)
}