我每天都在Scala学习新东西。我正在采取的当前路线是从java nio中提取功能并使Scala实现不受其影响。我观察过其他Scala专家如何使用java.nio.files包,以及FileVisitor接口以递归方式向下遍历带有子目录和文件的嵌套目录结构。
但是,我遇到了一个小问题。
我无法理解我注意到paulp维护的github上的一个实现,我无法理解。我将在这里提出他的代码,我的问题和疑虑:
import java.nio.file.{ FileVisitResult, SimpleFileVisitor }
trait PathVisitor extends FileVisitor[Path] {
def preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult
def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult
def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult
def visitFileFailed(file: Path, exc: IOException): FileVisitResult
}
好吧,他从FileVisitor扩展,这是一个Java接口:起初,我不确定Scala特性是否可以从Java接口扩展。我在REPL中对此进行了测试。显然这是好的。 REPL输出如下:
C:\用户\露露\文件\ GitHub的\ akkaexperiments>阶 欢迎使用Scala版本2.10.2(Java HotSpot(TM)64位服务器VM,Java 1.7.0_71)。 输入表达式以对其进行评估。 键入:帮助以获取更多信息。
阶> import java.nio.file。{FileVisitor}; import java.nio.file.FileVisitor
阶> import java.nio.file.Path import java.nio.file.Path
阶> trait PathVisitor扩展FileVisitor [Path] 定义特征PathVisitor
阶>
有了这个,我现在查看了FileVisitor.java的源代码。它在下面:这是paulp很有趣的地方。以下代码后面的解释如下。
public interface FileVisitor<T> {
FileVisitResult preVisitDirectory(T dir);
FileVisitResult preVisitDirectoryFailed(T dir, IOException exc);
FileVisitResult visitFile(T file, BasicFileAttributes attrs);
FileVisitResult visitFileFailed(T file, IOException exc);
FileVisitResult postVisitDirectory(T dir, IOException exc);
}
---------------------
paulp's code continues below:
object PathVisitor {
class Simple extends SimpleFileVisitor[Path] with PathVisitor { }
val Continue = FileVisitResult.CONTINUE
val SkipSiblings = FileVisitResult.SKIP_SIBLINGS
val SkipSubtree = FileVisitResult.SKIP_SUBTREE
val Terminate = FileVisitResult.TERMINATE
def apply(f: (Path, BasicFileAttributes) => FileVisitResult): PathVisitor = new Simple {
override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = f(file, attrs)
}
}
------
For context and comparison purposes here is the code for SimpleFileVisitor:
public class SimpleFileVisitor<T> implements FileVisitor<T> {
protected SimpleFileVisitor() {
}
@Override
public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
throws IOException
{
Objects.requireNonNull(dir);
Objects.requireNonNull(attrs);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(T file, BasicFileAttributes attrs)
throws IOException
{
Objects.requireNonNull(file);
Objects.requireNonNull(attrs);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(T file, IOException exc)
throws IOException
{
Objects.requireNonNull(file);
throw exc;
}
@Override
public FileVisitResult postVisitDirectory(T dir, IOException exc)
throws IOException
{
Objects.requireNonNull(dir);
if (exc != null)
throw exc;
return FileVisitResult.CONTINUE;
}
}
毕竟,我做了以下观察: class Simple扩展SimpleFileVisitor,它是Java FileVisitor接口的实现
也是特征PathVisitor中的paulp混合,其方法定义与Java FileVisitor接口中的方法定义完全相同。
这里令我困惑的是: 1)为什么他同时扩展SimpleFileVisitor,因为他也混合了PathVisitor特征? 2)当它们是相同的方法时,我们是不是要求类Simple简单地遵守SimpleVisitor契约和FileVisitor trait未实现的方法? 3)他包装Simple类,一组val来表示SimpleFileVisitor方法的返回类型和apply方法。那么,您认为这种结构背后的想法是什么?
我真的很想使用PaulP制定的结构,但这令人费解。它或许需要一些清理。 请指教。
答案 0 :(得分:1)
以这种方式做事的原因是提供无缝的Scala体验。首先,不是抽象你可能有访客的T
,而是第一个特征指定路径。如果你真的只对路径感兴趣,那么不必担心泛型。
然后他以Scala样式为您提供常量,这样您就不必从Java中获取它们。
他只是混合了SimpleFileVisitor
特征,就会给你一个特定路径的PathVisitor
,而不需要任何额外的工作。
现在,问题仍然存在:为什么这个而不是仅仅说
type PathVisitor = java.nio.file.FileVisitor
有两个原因。首先,类型别名不是真正的一流语言结构,因此您将倾向于看到Java类型而不是Scala类型(稍微不那么好)。此外,如果以这种方式进行设置,则可以在以后更轻松地将功能添加到框架中。如果你确定你不想添加任何东西,那么这样做的争论就会少一些。
现在,针对具体问题:
我们在PathVisitor中混合,因此我们有一个Scala特定的类型,我们可以移动和操作;我们从Java SimpleFileVisitor
获得实现,但是让它获取Scala特征。
要求尊重多种匹配的方法不是问题;相同的方法可以是多个特征的API的一部分。关键是你是否可以使用你想要的特征(即PathVisitor;答案是“是”)。
本地提供的Scala样式常量有助于清理导入并提供更加无缝的体验,apply
- 样式构建器代替new
。