令人困惑的scala语法

问题描述 投票:2回答:2

试图了解一些scala语法,以及在何处找到其规格。在下面,我对statefulMapConcat感到困惑。

签名是这个:

def statefulMapConcat [T](f:()=> Out => immutable.Iterable [T]):代表[T]

我们有

"be able to restart" in {
      Source(List(2, 1, 3, 4, 1))
        .statefulMapConcat(() => {
          var prev: Option[Int] = None
          x => {
            if (x % 3 == 0) throw ex
            prev match {
              case Some(e) =>
                prev = Some(x)
                (1 to e).map(_ => x)
              case None =>
                prev = Some(x)
                List.empty[Int]
            }
          }
        })
        .withAttributes(ActorAttributes.supervisionStrategy(Supervision.restartingDecider))
        .runWith(TestSink.probe[Int])
        .request(2)
        .expectNext(1, 1)
        .request(4)
        .expectNext(1, 1, 1, 1)
        .expectComplete()
    }

我不太满意

{
          var prev: Option[Int] = None
          x => {
            if (x % 3 == 0) throw ex
            prev match {
              case Some(e) =>
                prev = Some(x)
                (1 to e).map(_ => x)
              case None =>
                prev = Some(x)
                List.empty[Int]
            }
          }

对应于

Out =>不可变。Iterable[T]

有人可以帮我分解吗?

在我看来,x对应于Out,但随后我们在var prev: Option[Int] = None之前声明了一个变量

我想了解这些scala魔术,并从何处获得解释

scala akka-stream
2个回答
5
投票

这里要理解的两个关键概念是

  • 整个block expression的值是该块中last表达式的值,和
  • 函数是一流的

考虑以下块表达式

{
  var prev: Option[Int] = None
  42 // I am the last value of the block
}

因为块中的最后一个表达式的值为42,所以整个块的值为42类型的Int

类似地,考虑以下块表达式

{
  var prev: Option[Int] = None
  (x: Int) => { x + 1 } // I am also the last *value* of the block
}

因为块中的最后一个表达式的值为(x: Int) => { x + 1 },所以整个块的值为(x: Int) => { x + 1 }类型的值Int => Int

在两种情况下,由于表达式var prev: Option[Int] = None并非块中的最后一个表达式,因此它不会影响整个块的值的类型。


4
投票

快速说明。实际上,当您将单个arg编写为块时,没有内部花括号:

scala> def f(g: () => String => Int) = g()("42")
f: (g: () => String => Int)Int

scala> f(() => _.toInt)
res0: Int = 42

scala> f { () => s => s.toInt }
res1: Int = 42

scala> f ( () => s => s.toInt )
res2: Int = 42

scala> f { val x = "0" ; () => val y = x + "0" ; s => (s+y).toInt }
res3: Int = 4200

显示-Vprint:parser(2.12中的-Xprint,它可以正确解析,即使分号可能使人眼花]乱:

    val res3 = f({
      val x = "0";
      (() => {
        val y = x.$plus("0");
        ((s) => s.$plus(y).toInt)
      })
    })

编辑:神奇捕获的变量在堆上:

scala> { var i = 42 ; (j: Int) => j + i }
res1: Int => Int = $$Lambda$892/0x00000001006ec840@6e981e78

scala> :javap -c -
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
  public static final $line4.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line4/$read$$iw$$iw$
       3: dup
       4: invokespecial #25                 // Method "<init>":()V
       7: putstatic     #27                 // Field MODULE$:L$line4/$read$$iw$$iw$;
      10: bipush        42
      12: invokestatic  #33                 // Method scala/runtime/IntRef.create:(I)Lscala/runtime/IntRef;
      15: astore_0
      16: aload_0
      17: invokedynamic #52,  0             // InvokeDynamic #0:apply$mcII$sp:(Lscala/runtime/IntRef;)Lscala/runtime/java8/JFunction1$mcII$sp;
      22: putstatic     #54                 // Field res1:Lscala/Function1;
      25: return

  public scala.Function1<java.lang.Object, java.lang.Object> res1();
    Code:
       0: getstatic     #54                 // Field res1:Lscala/Function1;
       3: areturn

  public static final int $anonfun$res1$1(scala.runtime.IntRef, int);
    Code:
       0: iload_1
       1: aload_0
       2: getfield      #65                 // Field scala/runtime/IntRef.elem:I
       5: iadd
       6: ireturn

  public $line4.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #66                 // Method java/lang/Object."<init>":()V
       4: return
}
© www.soinside.com 2019 - 2024. All rights reserved.