我需要一些帮助,试图弄清楚如何重用模式匹配,我宁愿不重复(如果可能的话)。我在这里和谷歌进行了搜索,试验了暗示和差异但到目前为止还没有结果。
下面是两个方法,doSomething和doSomethingElse在Ids上包含相同的模式匹配。我希望通过传入一个函数来重用该模式。
这是初始设置。 (toPath和take2的实际实现并不真正相关。)
import java.nio.file.{Paths, Path}
import java.util.UUID
def take2(x: Long): String = {
(x % 100).toString.padTo(2, '0')
}
def take2(u: UUID): String = {
u.toString.take(2)
}
def toPath(x: Long): Path = {
Paths.get(s"$x")
}
def toPath(u: UUID): Path = {
Paths.get(u.toString)
}
case class Ids(id1: Option[Long], id2: Option[UUID])
def doSomething(ids: Ids): String = ids match {
case Ids(_, Some(uuid)) => take2(uuid)
case Ids(Some(long), _) => take2(long)
}
def doSomethingElse(ids: Ids) = ids match {
case Ids(_, Some(uuid)) => toPath(uuid)
case Ids(Some(long), _) => toPath(long)
}
doSomething(Ids(Some(12345L), None))
doSomethingElse(Ids(Some(12345L), None))
我想要的是这样的事情:
def execute[A](ids: Ids)(f: Any => A): A = ids match {
case Ids(_, Some(uuid)) => f(uuid)
case Ids(Some(long), _) => f(long)
}
def _doSomething(ids: Ids) = execute[String](ids)(take2)
//def _doSomething2(ids: Ids) = execute[Path](ids)(toPath)
我得到的错误是:
Error: ... type mismatch;
found : (u: java.util.UUID)String <and> (x: Long)String
required: Any => String
def _doSomething(ids: Ids) = execute[String](ids)(take2)
^ ^
如何让这些功能类型工作?
我的Scala版本2.11.2。
非常感谢任何帮助或指示。
答案 0 :(得分:1)
问题是您有两个不同的方法只是发生以共享相同的名称,例如“TAKE2”。当您尝试使用take2
时,您当然没有提供可以处理任何参数类型的函数(如Any => A
的要求);你甚至无法处理你想要的两种类型,因为它们是两种不同的方法!
在原始匹配语句中,您没有注意到这两个方法是两个共享相同名称的方法,因为编译器根据参数类型填写了正确的方法。没有一个功能说“插入我提供的名称然后坚持不同的方法”。 (好吧,你可以用宏来做,但是为了避免一点点重复,这非常复杂。)
现在编译器 足够智能,可以用你想要的方法创建一个函数。所以,如果你写了
def execute[A](ids: Ids)(f1: UUID => A, f2: Long => A): A = ids match {
case Ids(_, Some(uuid)) => f1(uuid)
case Ids(Some(long), _) => f2(long)
}
然后你可以
def doSomething(ids: Ids) = execute[String](ids)(take2, take2)
会减少重复次数。
或者,你可以写
import scala.util._
def take2(x: Long): String = (x % 100).toString.padTo(2, '0')
def take2(u: UUID): String = u.toString.take(2)
def take2(ul: Either[UUID, Long]): String = ul match {
case Left(u) => take2(u)
case Right(l) => take2(l)
}
(如果你在REPL中尝试这一点,请务必使用:paste
,这样所有三个一起定义。)
然后你写
def execute[A](ids: Ids)(f: Either[UUID, Long] => A): A = ids match {
case Ids(_, Some(uuid)) => f(Left(uuid))
case Ids(Some(long), _) => f(Right(long))
}
将使用三个take2
中的正确一个。 (与额外的参数装箱相关联会产生运行时损失,但我怀疑这是一个性能关键的代码路径。)
还有其他选项 - 例如,Shapeless提供了联合类型。或者你可以进行运行时模式匹配,如果你传递的信息既不是UUID
也不是Long
,就会抛出异常......但是这可能会导致以后遇到麻烦。