Scala:如何 return 一些或选项

Scala: How to return a Some or Option

我正在尝试增强以下代码: 我正在使用 java.nio.file 包将目录或文件表示为 Path。 所以这里是:

import java.nio.file.{Paths,DirectoryStream,Files,
                      Path,DirectoryIteratorException}

val path: Path = Paths.get(directoryPath) 
var directoryStream: Option[DirectoryStream[Path]] = None

// so far so good

try {
    directoryStream = Some(Files.newDirectoryStream(pathO))

    // this is where i get into trouble
    def getMeDirStream: DirectoryStream[Path] =
        if (!directoryStream.isEmpty && directoryStream.isDefined)
            getMeDirStream.get
        else
            None

    // invoke the iterator() method of dstream here
}

上面的代码无法编译,因为我不知道 return 在 else 中要做什么,现在,为了我的生活,我只能想出 None ,编译器根本不喜欢它,我想了解应该用什么来替代它。 我希望这个例子对我来说是 OptionSome 的学习课程。


好吧,这是我窒息的地方。我想检查 directoryStream 是否不为空并且已定义,然后如果是这种情况,我想调用 getMeDirStream.get 来调用它的 iterator() 方法。 Option 的 API 告诉我,如果选项为空,调用 get() 方法可能会导致 java.util.NoSuchElementException

如果 directoryStream 是空的,我想 return 而不是 None,因为 IntelliJ 告诉我 "Expression of type None.type doesn't conform to expected type DirectoryStream[Path]".

现在,我对此很天真。

我想了解以下内容:

  1. 除了None之外,else我应该return什么?

  2. 即使我正在检查 directoryStream 是否为空,我是否应该将 getMeDirStream.get 包装在带有 java.util.NoSuchElementException 的 try-catch 中?

  3. getMeDirStream.get中的try-catch的目的是什么,如果确实有这样的需要?

  4. 我怎样才能清理上面的代码以合并正确的检查 isDefined 和捕获适当的异常?

一旦我知道要在 else 中 return 做什么(并在必要时放入适当的 try-catch 块之后),我想在 [=33= 上调用 iterator() 方法]做一些下游操作。

SomeNoneOption的子类型,但更准确地说,它们实际上是Option或数据构造函数的两种不同情况。换句话说,即使 Scala 允许您直接调用 SomeNone,您仍然应该将它们的类型视为 Option。更重要的是,在任何情况下你都不应该调用 Option#get,因为它是不安全的。

Option的用意是表示一个值不存在的可能性。如果您关心这些错误,那么您可能应该考虑使用 Either(或者 Scalaz 的 Either 称为 \/)。

您可以将计算保留在 Option 上下文中,然后仅在以后提取值,或者提供默认值。

def fromTryCatch[A](a: => A): Either[Throwable, A] = try { Right(a) } catch { case e: Throwable => Left(e) }

val getMeDirStream: Option[java.util.Iterator[Path]] =
  for {
    path <- fromTryCatch(Paths.get(directoryPath)).toOption
    directoryStream <- fromTryCatch(Files.newDirectoryStream(pathO)).toOption
  } yield directoryStream.iterator()

稍后或紧接着,您可以获得迭代器,或提供默认值:

val iterator = getMeDirStream.getOrElse(java.util.Collections.emptyIterator[Path])

您的具体问题很难解决,因为不清楚您要实现的目标。特别是,当你问 try 块的目的是什么时......好吧,你写了它,所以只有你能回答。

一般来说,您从不Option 上调用 get。您要么使用模式匹配:

option match {
    case Some(value) => /* ... */
    case None =>        /* ... */
}

或者您使用 mapflatMapforeach 等方法(或 gpampara 代码使用的等效理解语法)。


我对gpampara回答的修改:

import scala.collection.convert.wrapAll._
import scala.util.Try
import java.nio.file.{Paths, Files, Path}

val getMeDirStream: Option[Iterator[Path]] =
  for {
    path <- Try(Paths.get("")).toOption
    directoryStream <- Try(Files.newDirectoryStream(path)).toOption
  } yield directoryStream.iterator

变化:

  • 使用 Try(...).toOption 代替 Either
  • scala.collection.convert 中使用隐式来 return 作为 Scala Iterator 的结果。

Try 类似于 Option。它有 SuccessFailure 子类型,而不是 SomeNone,失败案例包括 Throwable,而 None 只是一个没有附加信息的单例。