Scala: черта расширяет java.nio.file.FileVisitor

1

Я каждый день изучаю новые вещи в Scala. Текущий маршрут, который я принимаю, состоит в том, чтобы вытащить функциональность из java nio и сделать из них реализацию Scala. Я наблюдал, как другие эксперты Scala используют пакет java.nio.files и интерфейс FileVisitor для рекурсивного перехода по структуре вложенных каталогов с подкаталогами и файлами.

Но у меня возникла небольшая проблема. Я не могу понять

Я заметил реализацию на github, поддерживаемую paulp, что я не могу понять. Это его код, который я приведу здесь, с моими вопросами и проблемами:

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:\Users\lulu\Documents\GitHub\akkaexperiments> scala Добро пожаловать в версию Scala версии 2.10.2 (Java-сервер HotSpot TM TM, Java 1.7.0_71). Введите выражения, чтобы они были оценены. Тип: помощь для получения дополнительной информации.

scala> import java.nio.file. {FileVisitor}; import java.nio.file.FileVisitor

scala> import java.nio.file.Path import java.nio.file.Path

scala> trav PathVisitor расширяет свойство FileVisitor [Path] PathVisitor

Scala>


С этой точки зрения я теперь посмотрел на источник FileVisitor.java. Вот он внизу: здесь интригует папу. Пояснение следует после приведенного ниже кода.

  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 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 extends SimpleFileVisitor, который представляет собой реализацию интерфейса Java FileVisitor

Также paulp смешивает в trait PathVisitor, определения метода которого точно такие же, как и в интерфейсе Java FileVisitor.

Что меня озадачивает здесь: 1) почему он расширил SimpleFileVisitor в то же время, когда он также смешивается с признаком PathVisitor? 2) Разве мы не пытаемся просить класс Simple соблюдать как контракт SimpleVisitor, так и метод FileVisitor не реализовывать, когда они являются одними и теми же методами? 3) Он обертывает простой класс, кучу валов, чтобы представить возвращаемые типы методов SimpleFileVisitor и метод apply. Хорошо, так что, по-вашему, идея такой структуры?

Я бы очень хотел использовать структуру, изложенную PaulP, но это озадачивает. Возможно, это требует некоторой очистки. Пожалуйста, порекомендуйте.

  • 0
    Пол делает это «правильным путем», и мне бы хотелось, чтобы у меня было время объяснить, почему. (Существует более одного правильного пути, но это один из них.) Я надеюсь, что кто-то еще будет! Главное - подумать о том, что эти вещи делают для вашего API, ориентированного на Scala. Если разберешься сам, напиши ответ!
  • 0
    Спасибо за ваше понимание. Я обязательно сообщу о своих выводах. Это захватывающий поиск
Показать ещё 1 комментарий
Теги:
traits
nio

1 ответ

1
Лучший ответ

Причина этого - обеспечить бесшовный опыт Scala. Во- первых, вместо того, чтобы абстрагировать над какой T вы можете иметь посетителя для, первый признак определяет пути. Если вас действительно интересуют только пути, приятно не беспокоиться о дженериках.

Затем он предоставляет вам константы в стиле Scala, поэтому вам не нужно их захватывать с Java.

И он дает вам SimpleFileVisitor специфичный для SimpleFileVisitor без какой-либо дополнительной работы, просто смешивая в PathVisitor.

Теперь остается вопрос: зачем это делать, а не просто говорить

type PathVisitor = java.nio.file.FileVisitor

Есть две причины. Во-первых, типы псевдонимов не являются действительно первоклассными языковыми конструкциями, поэтому вы, скорее всего, будете видеть тип Java вместо Scala (немного менее приятный). Кроме того, если вы установите его таким образом, вы сможете более легко добавить функциональность в структуру позже. Если вы уверены, что не захотите что-либо добавить, тем меньше аргументов для этого.

Теперь, по конкретным вопросам:

  1. Мы смешиваем в PathVisitor, поэтому у нас есть Scala-специфический тип, который мы можем перемещать и манипулировать; мы получаем реализации Java SimpleFileVisitor но заставляем его забирать черту Scala.

  2. Просить соблюдать несколько методов, которые соответствуют, не является проблемой; тот же метод может быть частью API нескольких признаков. Ключ заключается в том, можете ли вы использовать желаемый признак (т.е. PathVisitor, ответ "да").

  3. Константы Scala -style, предоставляемые локально, помогают очистить ваш импорт и обеспечивают более бесшовный опыт, а также apply построитель -style вместо new.

  • 0
    Очень хорошее объяснение. Спасибо, что нашли время. «Есть две причины. Во-первых, псевдонимы типов на самом деле не являются первоклассными языковыми конструкциями, поэтому вы будете склонны видеть тип Java вместо типа Scala (немного менее приятный). Кроме того, если вы настроите его таким образом вы можете легче добавить функциональность в среду позже. Если вы уверены, что не хотите добавлять что-либо, у вас будет меньше аргументов сделать это таким образом ». Это лучшая часть.
  • 0
    «Просить соблюдать несколько методов, которые соответствуют, не проблема;» - удивительно. Я не знал, что это не будет проблемой или даже вменяемым.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню