Scala Cheat Sheet
Some Scala code examples which are by no means exhaustive but just some things I wanted to write down.
Options
val foo = Option(1) // or None
def bar(a: Int) = a + 1
// The match:
foo match {
case Some(f) => bar(f)
case None => -1
}
// ...is equivalent to:
foo map bar getOrElse -1
// ...or since Scala 2.10:
foo.fold(-1)(bar)
foo.isEmpty
// is equivalent to:
foo.fold(true)(_ => false)
Performant Matching
Compiling a match expression to a tableswitch or lookupswitch is much more performant because it results in a branch table rather than a decision tree. Such as in the code:
val i = 1
val x = i match {
case 1 => "Foo"
case 2 => "Bar"
case _ => "Baz"
}
The code with a value rather than an integer literal:
val i = 1
val Two = 2
val x = i match {
case 1 => "Foo"
case Two => "Bar"
case _ => "Baz"
}
…could not be compiled to a tableswitch. However the code:
import scala.annotation.switch
val i = 1
val Two = 2
val x = (i: @switch) match {
case 1 => "Foo"
case Two => "Bar"
case _ => "Baz"
}
…yields a warning that a tableswitch is not being created.
Enriching
// add method using 'pimp (enrich) my library pattern':
class SpecialList(list: List[String]) {
def special = list.filter(_.startsWith("foo"))
}
implicit def listToSpecialList(list: List[String]) = new SpecialList(list)
val list = List("foobar", "bazqux")
list.special
// add method using implicit classes (Scala 2.10 onwards):
implicit class SpecialList(list: List[String]) {
def special = list.filter(_.startsWith("foo"))
}
val list = List("foobar", "bazqux")
list.special
// 'add' method using composition
case class SpecialList(
list: List[String]
) {
def special = list.filter(_.startsWith("foo"))
}
val list = SpecialList(List("foobar", "bazqux"))
list.special
Loops
val items = Array("Hello", ", ", "World!")
val moreitems = Array.apply("Hello", ", ", "World!")
items.foreach(arg => println(arg))
items.foreach((arg: String) => println(arg))
val greetStrings = new Array[String](3)
greetStrings.update(0, "Hello")
greetStrings.update(1, ", ")
greetStrings.update(2, "World!")
// long-hand
for (i <- 0.to(2))
print(greetStrings.apply(i))
// but equivalent to
for (i <- 0 to 2)
print(greetStrings(i))
Lists
val emptyList = List()
val otherEmptyList = Nil
val items = List("foo", "bar", "baz")
val consStyleItems = "foo" :: "bar" :: "baz" :: Nil // cons prepend to front of Nil list
val concatStyleItems = List("foo", "bar") ::: List("baz")
items(2) // returns 'baz'
items.count(s => s.length == 3) // counts number of items with length of three chars
items.drop(2) // drops first two elements and returns rest of list
items.dropRight(2) // drops RIGHT MOST two elements and returns rest of list
items.exists(s => s == "bar") // boolean: contains item?
items.forall(s => s.startsWith("b")) // Boolean: all items start with "b"
items.forall(s => s.length == 3) // Boolean: all items three chars long
items.foreach(print)
items.isEmpty // Boolean
items.head // first item
items.init // all but the last item
items.last // the last item
items.tail // list minus first element
items.length // Int
val extraItems = items ::: List("password", "extra")
extraItems.filter(s => s.length == 3) // filters only strings with three chars
extraItems.foreach(s => s.startsWith("b"))
extraItems.map(s => "x" + s + "x")
extraItems.map(s => if (s == "password") { "[redacted]" } else { s })
extraItems.filterNot(s => s.length > 3) // new list without the matching items
extraItems.mkString(", ") // make a String out of the List
extraItems.reverse
extraItems.sortBy(s => s)
def printItemsImperative(items: Array[String]): Unit = {
var i = 0
while (i < items.length) {
println(items(i))
i += 1
}
}
def printItemsFunctional(items: Array[String]): Unit = {
for (item <- items)
println(item)
}
def printItemsFunctionalShort(items: Array[String]): Unit = {
items.foreach(println)
}
def printItemsPureFunctional(items: Array[String]) = {
items.mkString("\n")
}
val items = Array("one", "two", "three")
printItemsImperative(items)
printItemsFunctional(items)
printItemsFunctionalShort(items)
println(printItemsPureFunctional(items))
// makes the pure functional method easy to test:
assert(printItemsPureFunctional(items) == "one\ntwo\nthree")
val lines = Array("This is a line", "and this is another line", "so's this!")
val longestLine = lines.reduceLeft((a, b) => if (a.length > b.length) a else b)
Placeholder Syntax
val l = List(1, 3, 4, 6, 1, 3, 4, 9, 4, 6, 2)
l.filter((x: Int) => x > 4)
l.filter((x) => x > 4)
l.filter(x => x > 4)
l.filter(_ > 4)
Partially-applied functions
// the function
def sum (a: Int, b: Int, c: Int) = a + b + c
sum(1, 2, 3)
// create function value object
val s = sum _
s(1, 2, 3)
// is the short form of
s.apply(1, 2, 3) // which forwards params to sum then returns results
// apply to one of the params with two other new ones
val s2 = sum(1, _: Int, 3)
s2(2)
Parameters
// repeated parameters
def echo(args: String*) = for (arg <- args) println(arg)
val args = Array("one", "two", "three")
// pass each element of array to echo, rather than as an Array
echo(args: _ *)
// named arguments
def speed(distance: Float, time: Float): Float = distance / time
speed(100, 10)
speed(time = 10, distance = 100)
// default parameters
def greet(name: String = "World") = println(s"Hello, $name!")
greet("Beth")
greet()
Tail recursion vs imperative loop
def countFromRecursive(x: Int): Int =
if(x > 9) x
else countFromRecursive(x + 1)
def countFromLoop(x: Int): Int = {
var current = x
while (current < 10)
current += 1
current
}
// new stack frame for each call
def notTailRecursive(x: Int): Int =
if (x == 0) throw new Exception()
else notTailRecursive(x - 1) + 1
// single stack frame
def tailRecursive(x: Int): Int =
if (x == 0) throw new Exception()
else tailRecursive(x - 1)
// no tail-call optimisation
val funValueObject = nestedFunction _
def nestedFunction(x: Int) {
if (x != 0) {
println(x)
funValueObject(x - 1)
}
}
String interpolation
// s interpolator
val name = "World"
println(s"Hello, $name!")
// f interpolator, like printf
val population = 7.125d
println(f"Hello all $population%2.2f billion people in the world!")
// escaped string
s"x\ny"
// no formatting
raw"x\ny"
Tuples
// finite ordered list of heterogeneous immutable elements
val t = (4,3,2,1)
val sum = t._1 + t._2 + t._3 + t._4
t.productIterator.foreach(println)
val t = (1, "hello", Console)
// is equal to
val t = new Tuple3(1, "hello", Console)
Case class with trait-implemented function
trait Greeter {
val name: String
def render: String = "Hello, " + name + "!"
}
object Hello {
case class greet(name: String) extends Greeter
}
Hello.greet("World").render
Futures
import scala.util._
import scala.concurrent._
import ExecutionContext.Implicits.global
val f: Future[List[String]] = future {
Thread.sleep(200) // do something expensive
List("Hello, World!", "Goodbye, World!")
}
// then:
f onSuccess {
case messages => for (message <- messages) println(message)
}
f onFailure {
case t => println("An error has occured: " + t.getMessage)
}
// or, concisely:
f onComplete {
case Success(messages) => for (message <- messages) println(message)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
Serialized Futures using flatMap
import scala.util._
import scala.concurrent._
import ExecutionContext.Implicits.global
val f1: Future[String] = Future {
Thread.sleep(200)
"done 1..."
}
val f2: Future[String] = Future {
Thread.sleep(200)
"done 2..."
}
val serializedFutures: Future[String] = f1 flatMap(res1 => f2)
f1 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
f2 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
serializedFutures onComplete{
case resTry => println("Both Done: Success=" + resTry.isSuccess)
}
Serialized Futures using for comprehension
import scala.util._
import scala.concurrent._
import ExecutionContext.Implicits.global
val f1: Future[String] = Future {
Thread.sleep(200)
"done 1..."
}
val f2: Future[String] = Future {
Thread.sleep(200)
"done 2..."
}
def combine(s1: String, s12: String): String = "result"
val serializedFutures = for {
val1 <- f1
val2 <- f2
} yield combine(val1, val2)
f1 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
f2 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
serializedFutures onComplete{
case resTry => println("Both Done: Success=" + resTry.isSuccess)
}
BLOCKING Futures using Awaits
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
val f1: Future[String] = Future {
Thread.sleep(200)
"done 1..."
}
val f2: Future[String] = Future {
Thread.sleep(200)
"done 2..."
}
Await.result(f1, 10 seconds)
Await.result(f2, 10 seconds)
f1 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
f2 onComplete{
case Success(result) => println(result)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
XML
def fromXML(node: scala.xml.Node): TheThingIWant = new TheThingIWant {
val field = (node \ "field").text
}