Hidden features of Scala

2019-01-01 11:47发布

What are the hidden features of Scala that every Scala developer should be aware of?

One hidden feature per answer, please.

28条回答
其实,你不懂
2楼-- · 2019-01-01 11:55

You can use locally to introduce a local block without causing semicolon inference issues.

Usage:

scala> case class Dog(name: String) {
     |   def bark() {
     |     println("Bow Vow")
     |   }
     | }
defined class Dog

scala> val d = Dog("Barnie")
d: Dog = Dog(Barnie)

scala> locally {
     |   import d._
     |   bark()
     |   bark()
     | }
Bow Vow
Bow Vow

locally is defined in "Predef.scala" as:

@inline def locally[T](x: T): T = x

Being inline, it does not impose any additional overhead.

查看更多
刘海飞了
3楼-- · 2019-01-01 11:56

It's not exactly hidden, but certainly a under advertised feature: scalac -Xprint.

As a illustration of the use consider the following source:

class A { "xx".r }

Compiling this with scalac -Xprint:typer outputs:

package <empty> {
  class A extends java.lang.Object with ScalaObject {
    def this(): A = {
      A.super.this();
      ()
    };
    scala.this.Predef.augmentString("xx").r
  }
}

Notice scala.this.Predef.augmentString("xx").r, which is a the application of the implicit def augmentString present in Predef.scala.

scalac -Xprint:<phase> will print the syntax tree after some compiler phase. To see the available phases use scalac -Xshow-phases.

This is a great way to learn what is going on behind the scenes.

Try with

case class X(a:Int,b:String)

using the typer phase to really feel how useful it is.

查看更多
有味是清欢
4楼-- · 2019-01-01 11:57

Structural type definitions - i.e. a type described by what methods it supports. For example:

object Closer {
    def using(closeable: { def close(): Unit }, f: => Unit) {
      try { 
        f
      } finally { closeable.close }
    }
}

Notice that the type of the parameter closeable is not defined other than it has a close method

查看更多
伤终究还是伤i
5楼-- · 2019-01-01 11:58

Early Initialization:

trait AbstractT2 {
  println("In AbstractT2:")
  val value: Int
  val inverse = 1.0/value
  println("AbstractT2: value = "+value+", inverse = "+inverse)
}

val c2c = new {
  // Only initializations are allowed in pre-init. blocks.
  // println("In c2c:")
  val value = 10
} with AbstractT2

println("c2c.value = "+c2c.value+", inverse = "+c2c.inverse)

Output:

In AbstractT2:  
AbstractT2: value = 10, inverse = 0.1  
c2c.value = 10, inverse = 0.1

We instantiate an anonymous inner class, initializing the value field in the block, before the with AbstractT2 clause. This guarantees that value is initialized before the body of AbstractT2 is executed, as shown when you run the script.

查看更多
浪荡孟婆
6楼-- · 2019-01-01 11:59

Result types are dependent on implicit resolution. This can give you a form of multiple dispatch:

scala> trait PerformFunc[A,B] { def perform(a : A) : B }
defined trait PerformFunc

scala> implicit val stringToInt = new PerformFunc[String,Int] {
  def perform(a : String)  = 5
}
stringToInt: java.lang.Object with PerformFunc[String,Int] = $anon$1@13ccf137

scala> implicit val intToDouble = new PerformFunc[Int,Double] {
  def perform(a : Int) = 1.0
}
intToDouble: java.lang.Object with PerformFunc[Int,Double] = $anon$1@74e551a4

scala> def foo[A, B](x : A)(implicit z : PerformFunc[A,B]) : B = z.perform(x)
foo: [A,B](x: A)(implicit z: PerformFunc[A,B])B

scala> foo("HAI")
res16: Int = 5

scala> foo(1)
res17: Double = 1.0
查看更多
还给你的自由
7楼-- · 2019-01-01 12:00

You can compose structural types with the 'with' keyword

object Main {
  type A = {def foo: Unit}
  type B = {def bar: Unit}

  type C = A with B

  class myA {
    def foo: Unit = println("myA.foo")
  }


  class myB {
    def bar: Unit = println("myB.bar")
  }
  class myC extends myB {
    def foo: Unit = println("myC.foo")
  }

  def main(args: Array[String]): Unit = { 
    val a: A = new myA 
    a.foo
    val b: C = new myC 
    b.bar
    b.foo
  }
}
查看更多
登录 后发表回答