⏳
Loading cheatsheet...
Syntax, pattern matching, traits, implicits, collections, futures, Akka, and functional programming.
// ── Variables ──
val x: Int = 42 // immutable (preferred)
var y: String = "hello" // mutable (avoid)
val z = 3.14 // type inferred
// ── Basic Types ──
// Byte, Short, Int, Long, Float, Double, Char, Boolean, String
val i: Int = 42
val d: Double = 3.14
val c: Char = 'A'
val s: String = "hello"
val b: Boolean = true
// String interpolation
val name = "World"
s"Hello, $name!" // "Hello, World!"
s"2 + 3 = ${2 + 3}" // "2 + 3 = 5"
// Multiline string
val sql = """
|SELECT * FROM users
|WHERE active = true
""".stripMargin
// ── Type Hierarchy ──
// Any
// AnyVal (Int, Double, Boolean, Char, Unit)
// AnyRef (String, List, Map, etc.)
// Null (subclass of all AnyRef)
// Nothing (subtype of everything)
// Unit = () (like void)
// ── String Operations ──
"hello".toUpperCase // "HELLO"
"hello".toLowerCase // "hello"
" hello ".trim // "hello"
"hello".substring(1, 3) // "el"
"hello".reverse // "olleh"
"hello".replace("l", "r") // "herro"
"hello world".split(" ") // Array("hello", "world")
s"a,b,c".split(",") // Array("a", "b", "c")
"hello".length // 5
"hello".startsWith("hel") // true
"hello".contains("ell") // true
"ha".*3 // "hahaha"
"hello".mkString("[", ", ", "]") // "[h,e,l,l,o]"
// ── Control Flow ──
// If/else (expression!)
val result = if (x > 0) "positive" else "non-positive"
// Match (pattern matching)
val desc = x match {
case 1 => "one"
case 2 | 3 => "two or three"
case n if n > 10 => s"large: $n"
case _ => "other" // default
}
// For comprehension
val squares = for (i <- 1 to 5) yield i * i // Vector(1, 4, 9, 16, 25)
val evens = for {
i <- 1 to 10
if i % 2 == 0
} yield i // Vector(2, 4, 6, 8, 10)
// While loop (imperative)
var n = 5
while (n > 0) {
print(n + " ")
n -= 1
}| From | To | Method |
|---|---|---|
| String | Int | "42".toInt |
| String | Double | "3.14".toDouble |
| Int | String | 42.toString |
| Double | Int | 3.14.toInt |
| Any | String | s"value = $x" |
| Form | Behavior |
|---|---|
| s"text $var" | Simple variable |
| s"text ${expr}" | Expression |
| f"$name%s is $height%.2f" | printf-style |
| raw"no escape \n" | Raw string |
// ── List (immutable, linked list) ──
val nums = List(1, 2, 3, 4, 5)
val empty = Nil
val prepended = 0 :: nums // List(0, 1, 2, 3, 4, 5)
val appended = nums :+ 6 // List(1, 2, 3, 4, 5, 6)
val concat = List(1, 2) ++ List(3, 4) // List(1, 2, 3, 4)
nums.head // 1
nums.tail // List(2, 3, 4, 5)
nums.init // List(1, 2, 3, 4)
nums.last // 5
nums.isEmpty // false
nums.length // 5
// ── Vector (immutable, indexed) ──
val vec = Vector(1, 2, 3)
vec(0) // 1 (O(1) access)
vec.updated(0, 10) // Vector(10, 2, 3)
// ── Set (immutable, no duplicates) ──
val s = Set(1, 2, 3, 2, 1) // Set(1, 2, 3)
s + 4 // Set(1, 2, 3, 4)
s - 2 // Set(1, 3)
s ++ Set(4, 5) // Set(1, 2, 3, 4, 5)
// ── Map (immutable) ──
val m = Map("a" -> 1, "b" -> 2, "c" -> 3)
m("a") // 1
m.getOrElse("z", 0) // 0
m + ("d" -> 4) // new Map with entry
m - "b" // new Map without "b"
m.updated("a", 10) // Map("a" -> 10, ...)
// ── Mutable Collections ──
import scala.collection.mutable
val buf = mutable.ListBuffer(1, 2, 3)
buf += 4 // ListBuffer(1, 2, 3, 4)
buf -= 2 // ListBuffer(1, 3, 4)
buf.toList // List(1, 3, 4)
val mMap = mutable.Map("a" -> 1)
mMap("b") = 2 // mutable update
mMap += ("c" -> 3)
// ── Higher-Order Functions ──
val nums = List(1, 2, 3, 4, 5, 6)
nums.map(_ * 2) // List(2, 4, 6, 8, 10, 12)
nums.filter(_ > 3) // List(4, 5, 6)
nums.flatMap(x => List(x, x*10)) // List(1,10, 2,20, ...)
nums.reduce(_ + _) // 21
nums.foldLeft(0)(_ + _) // 21
nums.foldRight(0)(_ + _) // 21
nums.find(_ > 3) // Some(4)
nums.exists(_ > 5) // true
nums.forall(_ > 0) // true
nums.count(_ % 2 == 0) // 3
nums.sortWith(_ > _) // List(6, 5, 4, 3, 2, 1)
nums.groupBy(_ % 2) // Map(0 -> List(2,4,6), 1 -> ...)
nums.distinct // removes duplicates
nums.take(3) // List(1, 2, 3)
nums.drop(3) // List(4, 5, 6)
nums.takeWhile(_ < 4) // List(1, 2, 3)
nums.dropWhile(_ < 4) // List(4, 5, 6)
nums.zip(List("a","b","c")) // List((1,"a"), (2,"b"), ...)
nums.unzip // (List(1,2,3), List("a","b","c"))
nums.mkString(",") // "1,2,3,4,5,6"
// ── Option / Either ──
val opt: Option[Int] = Some(42)
opt.map(_ * 2) // Some(84)
opt.filter(_ > 10) // Some(42)
opt.getOrElse(0) // 42
opt match {
case Some(v) => s"Value: $v"
case None => "No value"
}
val either: Either[String, Int] = Right(42)
either.map(_ * 2) // Right(84)
either match {
case Right(v) => s"Success: $v"
case Left(e) => s"Error: $e"
}// ── Class ──
class Person(val name: String, var age: Int) {
def greet: String = s"Hi, I'm $name"
def haveBirthday(): Unit = age += 1
}
val p = new Person("Alice", 30)
p.name // "Alice" (val = immutable)
p.age // 30 (var = mutable)
p.haveBirthday()
p.age // 31
// ── Case Class (immutable, boilerplate-free) ──
case class User(name: String, email: String, age: Int = 0)
// No 'new' keyword
val u1 = User("Alice", "alice@example.com", 30)
val u2 = User("Bob", "bob@example.com")
// Copy with changes
val u3 = u1.copy(age = 31) // User("Alice", "alice@example.com", 31)
// Built-in equals, hashCode, toString
u1 == User("Alice", "alice@example.com", 30) // true
u1.toString // "User(Alice,alice@example.com,30)"
// Pattern matching on case class
u1 match {
case User("Alice", email, _) => s"Alice's email: $email"
case User(name, _, age) if age > 25 => s"$name is over 25"
case _ => "Unknown user"
}
// ── Trait (like interface with implementation) ──
trait Greeter {
def greet(name: String): String
}
trait Polite extends Greeter {
override def greet(name: String): String = s"Good day, $name"
}
class EnglishGreeter extends Polite
class CasualGreeter extends Greeter {
def greet(name: String): String = s"Hey $name!"
}
// Mixin traits (stackable modifications)
trait UpperCaseGreeter extends Greeter {
abstract override def greet(name: String): String =
super.greet(name).toUpperCase
}
val g = new EnglishGreeter with UpperCaseGreeter
g.greet("Alice") // "GOOD DAY, ALICE"
// ── Sealed Trait (restricted hierarchy) ──
sealed trait Shape {
def area: Double
}
case class Circle(radius: Double) extends Shape {
def area: Double = Math.PI * radius * radius
}
case class Rectangle(width: Double, height: Double) extends Shape {
def area: Double = width * height
}
case class Triangle(base: Double, height: Double) extends Shape {
def area: Double = 0.5 * base * height
}
// Exhaustive pattern matching on sealed trait
def describe(shape: Shape): String = shape match {
case Circle(r) => s"Circle with radius $r"
case Rectangle(w, h) => s"Rectangle $w x $h"
case Triangle(b, h) => s"Triangle base=$b height=$h"
}
// ── Object (singleton) ──
object MathUtils {
def square(x: Int): Int = x * x
def cube(x: Int): Int = x * x * x
}
MathUtils.square(5) // 25
// ── Companion Object ──
class Counter private (private var count: Int) {
def increment(): Unit = count += 1
def get: Int = count
}
object Counter {
def apply(start: Int = 0): Counter = new Counter(start)
}
val c = Counter(10) // uses apply
c.increment()
c.get // 11| Feature | Class | Case Class |
|---|---|---|
| Mutable fields | Yes (var) | No (val only) |
| Equals/hashCode | Reference | Structural |
| toString | ClassName@hash | Readable |
| Pattern matching | Limited | Full extraction |
| Copy method | No | Yes (copy()) |
| new keyword | Required | Optional |
| Serializable | No | Yes |
| Pattern | Matches |
|---|---|
| case x if cond | Guard clause |
| case (a, b) | Tuple extraction |
| case a :: tail | List head/tail |
| case Some(x) | Option extraction |
| case _: Type | Type check |
| case User(n, e, a) | Case class extraction |
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
// ── Creating Futures ──
val f1: Future[Int] = Future {
Thread.sleep(1000)
42
}
// Map / flatMap / filter (monadic)
val f2: Future[Int] = f1.map(_ * 2) // Future(84)
val f3: Future[Int] = f1.flatMap(x => Future(x + 1)) // Future(43)
val f4: Future[Int] = f1.filter(_ > 0) // Future(42)
// Transform
val f5: Future[String] = f1.map(x => s"Result: $x")
// for-comprehension
val f6: Future[String] = for {
a <- Future { fetchUser(1) }
b <- Future { fetchOrders(a.id) }
} yield s"${a.name} has ${b.length} orders"
// Recover from errors
val f7: Future[Int] = Future(10 / 0).recover {
case _: ArithmeticException => 0
}
val f8: Future[Int] = Future(10 / 0).recoverWith {
case _: ArithmeticException => Future(0)
}
val f9: Future[Int] = Future(10 / 0).fallbackTo(Future(-1))
// ── Callbacks ──
f1.onComplete {
case Success(value) => println(s"Got: $value")
case Failure(error) => println(s"Error: ${error.getMessage}")
}
// ── Composing Multiple Futures ──
val all: Future[List[Int]] = Future.sequence(
List(Future(1), Future(2), Future(3))
) // Future(List(1, 2, 3))
val first: Future[Int] = Future.firstCompletedOf(
List(Future { slowCompute() }, Future { fastCompute() })
)
// Blocking (avoid in production!)
val result = Await.result(f1, 5.seconds)
val result2 = Await.ready(f1, 5.seconds).value.get
// ── Akka Actor (simplified) ──
import akka.actor.{Actor, ActorSystem, Props}
class CounterActor extends Actor {
var count: Int = 0
def receive: Receive = {
case "increment" => count += 1
case "get" => sender() ! count
case "reset" => count = 0
}
}
val system = ActorSystem("MySystem")
val counter = system.actorOf(Props[CounterActor](), "counter")
counter ! "increment"
counter ! "increment"
counter ! "get"
// Receive reply (using ask pattern)
import akka.pattern.ask
import akka.util.Timeout
implicit val timeout: Timeout = 3.seconds
val futureCount = (counter ? "get").mapTo[Int]
futureCount.foreach(println) // prints 2| Method | Description |
|---|---|
| map(f) | Transform success value |
| flatMap(f) | Chain futures |
| filter(pred) | Success only if pred matches |
| recover(pf) | Handle errors |
| recoverWith(pf) | Fallback to another Future |
| fallbackTo(f) | Use f if this fails |
| andThen(f) | Side-effect callback |
| zip(other) | Combine two futures to tuple |
| Type | Description |
|---|---|
| ! | Fire-and-forget (tell) |
| ? (ask) | Expect reply (Future) |
| Forward | Forward message with original sender |
| PipeTo | Send future result to actor |
map, flatMap, and for comprehensions to compose futures. Block only at the boundary (e.g., in main or tests).// ── Implicit Parameters ──
implicit val timeout: Int = 5000
def fetchWithTimeout(url: String)(implicit t: Int): String = {
s"Fetching $url with timeout $t"
}
fetchWithTimeout("http://example.com") // uses implicit
// ── Implicit Conversions ──
implicit def intToString(x: Int): String = x.toString
// ── Type Classes (via implicits) ──
trait Show[A] {
def show(a: A): String
}
implicit val showInt: Show[Int] = new Show[Int] {
def show(a: Int): String = s"Int($a)"
}
implicit val showString: Show[String] = new Show[String] {
def show(a: String): String = s"String($a)"
}
def prettyPrint[A](a: A)(implicit s: Show[A]): Unit = {
println(s.show(a))
}
prettyPrint(42) // uses implicit showInt
prettyPrint("hello") // uses implicit showString
// ── Extension Methods (Scala 3 style) ──
extension (s: String) {
def greet: String = s"Hello, $s!"
}
"Alice".greet // "Hello, Alice!"
// ── Generic Methods ──
def head[A](list: List[A]): Option[A] = list.headOption
def identity[A](a: A): A = a
// Variance
class Container[+A] // Covariant: Container[Animal] <: Container[Cat]
class Box[-A] // Contravariant: Box[Cat] <: Box[Animal]
class Cell[A] // Invariant: no subtyping relationship
// ── Context Bounds (sugar for implicits) ──
def max[A](a: A, b: A)(using ord: Ordering[A]): A =
if ord.compare(a, b) > 0 then a else b
// ── Union & Intersection Types (Scala 3) ──
type StringOrInt = String | Int
type Resettable = { def reset(): Unit }
type ResettableCat = Resettable & Cat
// ── Enum (Scala 3) ──
enum Color(val rgb: Int):
case Red extends Color(0xFF0000)
case Green extends Color(0x00FF00)
case Blue extends Color(0x0000FF)
Color.Red.ordinal // 0
Color.Red.rgb // 0xFF0000
// Enum with cases
enum Result[+A, +B]:
case Ok(value: B)
case Err(error: A)// ── build.sbt ──
name := "my-project"
version := "0.1.0"
scalaVersion := "2.13.14"
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.10.0",
"com.typesafe.akka" %% "akka-actor" % "2.8.5",
"org.scalactic" %% "scalactic" % "3.2.18",
"org.scalatest" %% "scalatest" % "3.2.18" % Test,
)
// ── Common SBT Commands ──
// sbt compile # compile source
// sbt test # run tests
// sbt testOnly *.MySpec # run specific test
// sbt run # run main class
// sbt console # Scala REPL with project
// sbt assembly # build fat JAR (needs plugin)
// sbt clean # clean build artifacts
// sbt package # create JAR
// sbt dependencyTree # show dependency tree
// sbt update # update dependencies| Scope | Use Case |
|---|---|
| Compile | Default (production code) |
| Test | Test dependencies |
| Runtime | Runtime only |
| Provided | Expected from container |
| Optional | Optional dependency |
| Library | Purpose |
|---|---|
| Cats / Cats Effect | Functional programming |
| Akka | Actor model, HTTP |
| Play Framework | Web framework |
| ZIO | Async, typed effects |
| Scalatest | Testing |
| Circe | JSON parsing |
| Slick | Database access |
| Http4s | HTTP server/client |