Scala:trait扩展了java.nio.file.FileVisitor

时间:2015-03-30 19:23:58

标签: java scala nio traits

我每天都在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制定的结构,但这令人费解。它或许需要一些清理。 请指教。

1 个答案:

答案 0 :(得分:1)

以这种方式做事的原因是提供无缝的Scala体验。首先,不是抽象你可能有访客的T,而是第一个特征指定路径。如果你真的只对路径感兴趣,那么不必担心泛型。

然后他以Scala样式为您提供常量,这样您就不必从Java中获取它们。

他只是混合了SimpleFileVisitor特征,就会给你一个特定路径的PathVisitor,而不需要任何额外的工作。

现在,问题仍然存在:为什么这个而不是仅仅说

type PathVisitor = java.nio.file.FileVisitor

有两个原因。首先,类型别名不是真正的一流语言结构,因此您将倾向于看到Java类型而不是Scala类型(稍微不那么好)。此外,如果以这种方式进行设置,则可以在以后更轻松地将功能添加到框架中。如果你确定你不想添加任何东西,那么这样做的争论就会少一些。

现在,针对具体问题:

  1. 我们在PathVisitor中混合,因此我们有一个Scala特定的类型,我们可以移动和操作;我们从Java SimpleFileVisitor获得实现,但是让它获取Scala特征。

  2. 要求尊重多种匹配的方法不是问题;相同的方法可以是多个特征的API的一部分。关键是你是否可以使用你想要的特征(即PathVisitor;答案是“是”)。

  3. 本地提供的Scala样式常量有助于清理导入并提供更加无缝的体验,apply - 样式构建器代替new