鉴于此RichFile
类及其伴随对象:
class RichFile(filePath: String) {
val file = new File(filePath)
}
object RichFile {
def apply(filePath: String) = new RichFile(filePath)
def unapply(rf: RichFile) = {
if (rf == null || rf.file.getAbsolutePath().length() == 0)
None
else {
val basename = rf.file.getName()
val dirname = rf.file.getParent()
val ei = basename.indexOf(".")
if (ei >= 0) {
Some((dirname, basename.substring(0, ei), basename.substring(ei + 1)))
} else {
Some((dirname, basename, ""))
}
}
}
def unapplySeq(rf: RichFile): Option[Seq[String]] = {
val filePath = rf.file.getAbsolutePath()
if (filePath.length() == 0)
None
else
Some(filePath.split("/"))
}
}
基本上我想将文件路径的所有组件都提取为序列。为什么通配符匹配在以下代码中不起作用?特别是第一个case
语句我收到错误star patterns must correspond with varargs parameters
。
val l = List(
RichFile("/abc/def/name.txt"),
RichFile("/home/cay/name.txt"),
RichFile("/a/b/c/d/e"))
l.foreach { f =>
f match {
case RichFile(_*) => println((x, y))
case RichFile(a, b, c) => println((a, b, c))
}
}
我也希望匹配它们,就像我们匹配Scala中的列表一样:
l.foreach { f =>
f match {
case a::b::"def"::tail => println((a, tail))
case RichFile(_*) => println((x, y))
case RichFile(a, b, c) => println((a, b, c))
}
}
如何使用unapplySeq
?
答案 0 :(得分:4)
看起来问题只是你同时拥有unapply
和unapplySeq
,所以当你在case RichFile
中只有一个参数时,scala对于哪种不适用你感到困惑正在努力做到。解决此问题的方法是拥有两个对象,一个包含unapply
,另一个包含unapplySeq
,因此用法是明确的。
class RichFile(filePath: String) {
val file = new File(filePath)
override def toString = f"RichFile($filePath)"
}
object RichFile {
def apply(filePath: String) = new RichFile(filePath)
def unapply(rf: RichFile) = {
if (rf == null || rf.file.getAbsolutePath.isEmpty) None
else {
val basename = rf.file.getName
val dirname = rf.file.getParent
val (name, ext) = basename.split("\\.", 2) match {
case Array(name, ext) => (name, ext)
case Array(name) => (name, "")
}
Some((dirname, name, ext))
}
}
}
object RichFilePath {
def unapplySeq(rf: RichFile): Option[Seq[String]] = {
val filePath = rf.file.getAbsolutePath()
if (filePath.isEmpty) None
else Some(filePath.split("/"))
}
}
val l = List(
RichFile("/abc/def/name.txt"),
RichFile("/home/cay/name.txt"),
RichFile("/a/b/c/d/e"),
RichFile("/y/z"))
l.foreach { f =>
f match {
case RichFilePath(a, b, c) => println("RichFilePath -> " + (a, b, c))
case RichFile(f) => println("RichFile -> " + f)
}
}
打印:
RichFile -> (/abc/def,name,txt)
RichFile -> (/home/cay,name,txt)
RichFile -> (/a/b/c/d,e,)
RichFilePath -> (,y,z)
关于::
语法,您不能使用::
,因为它已经定义并且仅适用于列表。此外,您不希望::
,因为以:
结尾的运算符是右关联的。这对于List匹配是有意义的,因为该项位于左侧,其余位于右侧。对于您的应用程序,我假设您希望匹配的读取方式与目录结构相同:右侧是文件名,左侧是“rest”。因此,您可以为此定义自己的运算符:
object --> {
def unapply(rf: RichFile): Option[(RichFile, String)] = {
if (rf.file.getAbsolutePath.isEmpty)
None
else {
val f = rf.file.getAbsoluteFile
Some((RichFile(f.getParent), f.getName))
}
}
}
l.foreach { f =>
f match {
case a --> b --> c => println(f"$a\t$b\t$c")
}
}
打印
RichFile(/abc) def name.txt
RichFile(/home) cay name.txt
RichFile(/a/b/c) d e
RichFile(/) y z