为什么在对 Try[Unit] 的结果使用 for comprehension 时会出现(不一致的)编译器错误?

Why am I getting an (inconsistent) compiler error when using a for comprehension with a result of Try[Unit]?

我在我的代码库中的一个常见模式是使用 Try[Unit] 定义方法,以指示该方法正在做一些事情(比如将事务长写入 SaaS REST 端点),而没有有趣的 return 结果,我想捕获任何遇到的错误并将遇到的任何错误发送给 stdout。我读过另一个 Whosebug thread this is entirely acceptable (另请参阅问题的第二条评论)。

特别明确地避免实际抛出和捕获异常,这在大多数 JVM 实现中是非常昂贵的activity。这意味着任何使用 Try() 习语的答案都无助于解决我的问题。

我有以下代码(从我的现实生活场景中大大简化):

def someMethod(transactionToLog: String): Try[Unit] = {
  val result =
    for {
      _ <- callToSomeMethodReturningATryInstance
    } yield Unit
  result match {
    case Success(_)
      //Unit
    case Failure(e) ->
      println(s"oopsie - ${e.getMessage}")
  }
  result
}

有时这段代码编译得很好。有时它没有。如果没有,它会给我以下编译错误:

Error:(row, col) type mismatch;
 found   : scala.util.Try[Unit.type]
 required: scala.util.Try[Unit]
    result
    ^

有时 IntelliJ 语法高亮显示代码正常。其他时间it shows an error(和上面那个大致一样)。有时我会收到编译器错误,但不会出现更严重的错误。有时它编译得很好,我只得到一个荧光笔错误。到目前为止,我很难找到一个完美的 "example" 来捕获编译器错误。

我试图通过将 .asInstanceOf[Unit] 添加到 for 理解的结果来 "cure" 这个问题。这让它通过了编译器。但是,现在我收到 java.lang.ClassCastException: scala.Unit$ cannot be cast to scala.runtime.BoxedUnit 的运行时异常。这自然比原来的编译错误差了无数倍

那么,两个问题:

  1. 假设 Try[Unit] 无效,Scala 惯用的(甚至只是首选的)方法是什么来指定 Try 而 return 没有用Success 结果?

  2. 假设 Try[Unit] 有效,我如何克服编译错误(如上所述)?


旁注:
我一定是一年前遇到过这个问题,不记得细节了。我创建了下面的解决方案,我的代码库中都有它。但是,最近我开始在很多地方使用 Future[Unit]。当我第一次尝试 Try[Unit] 时,它似乎起作用了。但是,它现在导致编译和 IDE highlighting issues 的次数已经增加了很多。所以,我想就如何继续进行做出最终决定,这与现有的(甚至正在出现的)一致并且是 Scala 惯用的。

package org.scalaolio.util

/** This package object serves to ease Scala interactions with mutating
 *  methods.
 */
package object Try_ {
  /** Placeholder type for when a mutator method does not intend to
   *  return anything with a Success, but needs to be able to return a
   *  Failure with an unthrown Exception.
   */
  sealed case class CompletedNoException private[Try_] ()

  /** Placeholder instance for when a mutator method needs to indicate
   *  success via Success(completedNoExceptionSingleton)
   */
  val completedNoExceptionSingleton = new CompletedNoException()
}

yield Unit 替换为 yield ()

Unit 是一种类型 - () 是类型 Unit.

的值(也是唯一可能的值)

这就是为什么 for { _ <- expr } yield Unit 会导致 Try[Unit.type],正如 yield String 会导致 Try[String.type]