如何明确返回单位?

时间:2018-11-21 15:43:33

标签: scala functional-programming

使用Unit()从方法中显式返回Unit类型的正确方法是什么?在我看来,这两种方法在我尝试过的所有情况下都有效。

对于上下文,如果我正在编写一个具有副作用的方法并返回调用另一个方法的Unit,则该情况经常发生,该方法也执行副作用,但是返回一些值而不是Unit。例如

def effectAndReturn(): String = {
  val msg = "Hello, SO"
  println(msg)
  msg
}

def doEffect(): Unit = {
  val _ = effectAndReturn()
  () // `Unit` also works here
}

据我了解,()是存在的唯一类型Unit的值。返回Unit中的令牌doEffect()引用的是Unit伴随对象;我很困惑如何返回一个值,因为甚至没有定义任何apply方法。据我所知,返回给定抽象类类型的伴随对象作为返回值无效。

将它们放入Scala REPL中也很有趣

scala> val parenUnit = ()
parenUnit: Unit = ()

scala> parenUnit
// Returns blank line

scala> val wordUnit = Unit
wordUnit: Unit.type = object scala.Unit

scala> wordUnit
res1: Unit.type = object scala.Unit

scala> res1
res2: Unit.type = object scala.Unit

()只是一个Unit值,而Unit会返回一个类型,这对我来说没有意义,因为据我所知,没有其他伴随对象会这样做。我的猜测是,与任何其他类型相比,编译器都以特定且独特的方式处理Unit,但究竟如何呢?

2 个答案:

答案 0 :(得分:6)

所以,我们有:

  • Unit 类型
  • 单位值为(),类型为Unit
  • Unit伴随对象,引起混乱。它是类型Unit不是。它的类型为Unit.type(它自己的单例类型)。但是... Scala会自动将所有内容隐式转换为Unit,这就是为什么可以在需要Unit类型的地方使用它的原因。

TLDR:使用()

答案 1 :(得分:1)

假设在名为TestUnit的类中有两个方法:

class TestUnit {
  def foo(): Unit = 2217
  def bar(): Int = 1478
}

让我们看看它的字节码:

  // access flags 0x1
  public foo()V
   L0
    LINENUMBER 4 L0
    SIPUSH 2217
    POP
    RETURN // returns void
   L1
    LOCALVARIABLE this Lunit/TestUnit; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public bar()I
   L0
    LINENUMBER 5 L0
    SIPUSH 1478
    IRETURN // returns integer because it is declared in method
   L1
    LOCALVARIABLE this Lunit/TestUnit; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

我的假设是-Scala编译器仅在将RETURN声明为返回类型的每个方法中放置Unit指令(返回void)。 (您可以查看列表here

因此,您可以返回doEffect()中的任何类型。但是正如 @ghik 所说,最好使用()