Skip to content

Instantly share code, notes, and snippets.

@fuyufjh
Last active July 15, 2018 16:00
Show Gist options
  • Save fuyufjh/64bfba3c6989aaafacc69689ef76aba1 to your computer and use it in GitHub Desktop.
Save fuyufjh/64bfba3c6989aaafacc69689ef76aba1 to your computer and use it in GitHub Desktop.
Scala Cheatsheet
import akka.actor._
import akka.pattern.ask
import scala.collection.mutable
import scala.concurrent.Await
import scala.concurrent.duration._
case class AddCount(word: String)
case class ReportCount(word: String)
class WordCountActor extends Actor {
private val counter = mutable.Map[String, Int]()
override def receive: Receive = {
case AddCount(word) =>
counter.put(word, counter.getOrElse(word, 0))
case ReportCount(word) =>
sender ! counter.getOrElse(word, 0)
}
}
object UseActor extends App {
val system = ActorSystem("example")
val counter = system.actorOf(Props[WordCountActor])
counter ! AddCount("hello")
counter ! AddCount("world")
val resultFuture = counter ? ReportCount("hello")
println(s"Count of 'hello' is ${Await.result(resultFuture, 2.seconds)}")
val terminateFuture = system.terminate()
Await.ready(terminateFuture, Duration.Inf)
}
// For loop
for (i <- 1 to 3) {
print(s"$i,") // got: 1,2,3,
}
for (i <- 1 until 3) {
print(s"$i,") // got: 1,2,
}
(1 to 3).foreach(i => print(s"$i,"))
// Tuple and multiple return values
def getPersonInfo(primaryKey: Int): (String, String, String) = {
("Venkat", "Subramanian", "[email protected]")
}
val (firstName, lastName, emailAddress) = getPersonInfo(123)
// Variable number of arguments
def max(values: Int*): Int = {
values.foldLeft(values(0))(Math.max)
}
max(2, 5, 3, 7, 1, 6)
// Default values for argument
def mail(destination: String = "head office", mailClass: String = "first"): Unit = {
println(s"sending to $destination by $mailClass class")
}
mail("Houston office", "Priority")
mail("Houston office")
mail()
// Named argument
mail(mailClass = "Priority", destination = "Houston office")
// Implicit parameters
class Wifi(name: String) {
override def toString = name
}
def connectToNetwork(user: String)(implicit wifi: Wifi) {
println(s"User: $user connected to WIFI $wifi")
}
def atOffice(): Unit = {
implicit def officeNetwork: Wifi = new Wifi("office-network")
connectToNetwork("Jill Coder")
connectToNetwork("Jill Coder")(officeNetwork) // equivalent
}
atOffice()
// Multiline String
val str = """In his famous inaugural speech, John F. Kennedy said
|"And so, my fellow Americans: ask not what your country can do
|for you-ask what you can do for your country." He then proceeded
|to speak to the citizens of the World..."""
println(str)
// String interpolation
val product = "ticket"
val price = 25.12
val discount = 10
println(s"On $product $discount% saves $$${price * discount / 100.00}") // s-interpolator
println(f"On $product%s $discount%% saves $$${price * discount / 100.00}%2.2f") // f-interpolator
// Operator overload
case class Complex(real: Double, imaginary: Double) {
def +(o: Complex): Complex = Complex(real + o.real, imaginary + o.imaginary)
def *(o: Complex): Complex = Complex(real * o.real - imaginary * o.imaginary, real * o.imaginary + imaginary * o.real)
override def toString: String = f"$real%f$imaginary%+fi"
}
val c1 = Complex(1, 4)
val c2 = Complex(2, -3)
val c3 = Complex(2, 2)
println(s"$c1 + $c2 * $c3 = ${c1 + c2 * c3}") // Multiply first, then add
// Equality
val str1 = "hello"
val str2 = new String("hello")
println(str1 == str2) // Got true, equivalent to Java's str1.equals(str2)
println(str1 eq str2) // Got false, equivalent to Java's str1 == str2
// A simple class
class Person(val firstName: String, val lastName: String) {
var position: String = _ // default initial value (null for AnyRef)
println(s"Creating $toString") // this line is part of constructor
def this(firstName: String, lastName: String, position: String) { // auxiliary constructor
this(firstName, lastName) // must call primary constructor first
this.position = position
}
override def toString = s"$firstName $lastName holds $position position"
}
val john = new Person("John", "Smith", "Analyst")
val bill = new Person("Bill", "Walker")
// Type alias
class PoliceOfficer(val name: String)
object CopApp extends App {
type Cop = PoliceOfficer
val topCop = new Cop("Jack")
}
// Class inherit (the override keyword)
class Vehicle(val id: Int, val year: Int) {
override def toString = s"ID: $id Year: $year"
}
class Car(override val id: Int, override val year: Int, var fuelLevel: Int) extends Vehicle(id, year) {
override def toString = s"${super.toString} Fuel Level: $fuelLevel"
}
// Type Parameters (generic class)
class Message[T](val content: T) {
override def toString = s"message content is $content"
def is(value: T) = value == content
}
// Companion object
class Marker private (val color: String) { // private primary constructor
override def toString = s"marker color $color"
}
object Marker {
def getMarker(color: String): Marker = new Marker(color)
def apply(color: String): Marker = new Marker(color)
}
println(Marker.getMarker("blue"))
println(Marker("blue")) // equivalent to Marker.apply
// Enumeration class
object Currency extends Enumeration {
type Currency = Value // 'Currency' is not only an object but also a class, so that you may use 'val c: Currency'
val CNY, GBP, INR, JPY, USD = Value
}
import java.time.DayOfWeek
import Currency._
val currency: Currency
Currency.values.foreach(c => println(c))
// Package object
/*
package foo
package object bar {
def func() = ...
}
*/
// Generics (Type Inference)
def someOp(number: Int) = { // So result is Int because Nothing is always subclass of other classes
if (number < 10) number * 2 // this branch returns Int
else throw new IllegalArgumentException // this branch returns Nothing
}
// Option type
def commentOnPractice(input: String): Option[String] = {
input match {
case "test" => Some("good")
case "hack" => Some("bad")
case _ => None
}
}
val comment = commentOnPractice("hack")
println(comment.getOrElse("Found no comment"))
// Either type
def compute(input: Double): Either[String, Double] = {
if (input > 0) Right(math.sqrt(input)) // usually Right for normal result
else Left("Error: invalid input") // ... and Left for error
}
def displayResult(result: Either[String, Double]): Unit = {
result match {
case Right(value) => println(s"result: $value")
case Left(error) => println(s"error: $error")
}
}
displayResult(compute(1.2))
// Support covariance (accept any subclass)
class Pet(val name: String) {
override def toString: String = name
}
class Cat(override val name: String) extends Pet(name)
def payWithPets[T <: Pet](pets: Array[T]): Unit = {
println("Playing with pets: " + pets.mkString(", "))
}
val cats = Array(new Cat("Rover"), new Cat("Comet"))
payWithPets(cats) // OK!
// Support contravariance (accept any superclass)
def copyPets[S, D >: S](fromPets: Array[S], toPets: Array[D]): Unit = {
for (i <- fromPets.indices) toPets(i) = fromPets(i)
}
val pets = new Array[Pet](10)
copyPets(cats, pets) // OK!
// Support covariance/contravariance for customized collection
class MyList[+T] // ...
val list: MyList[Any] = new MyList[Int] // OK!
// Implicit function
class DateHelper(offset: Int) {
def days(when: String) = {
val today = java.time.LocalDate.now
when match {
case "ago" => today.minusDays(offset)
case "from_now" => today.plusDays(offset)
}
}
}
object DateHelper {
import scala.language.implicitConversions // otherwise the compiler will complain about 'implicit' keyword
val ago = "ago"
val from_now = "from_now"
implicit def convertInt2DateHelper(offset: Int): DateHelper = new DateHelper(offset)
}
{
import DateHelper._
println(2 days ago)
}
// Implicit class
object DateUtil {
val ago = "ago"
val from_now = "from_now"
implicit class DateHelper(val offset: Int) extends AnyVal { // 'extends AnyVal' eliminates the cost of newing object
def days(when: String) = {
val today = java.time.LocalDate.now
when match {
case "ago" => today.minusDays(offset)
case "from_now" => today.plusDays(offset)
}
}
}
}
{
import DateUtil._
println(2 days ago)
}
// String interpolator
val expr1 = "expr1"
val expr2 = "expr2"
val text1 = s"text1 $expr1 text2 $expr2" // Equivalent to: new StringContext("text1 ", " text2 ", "").s(expr1, expr2)
// High-order function
def printValue(generator: () => Int): Unit = {
println(s"Generated value is ${generator()}")
}
printValue(() => 42)
// Currying
val array = Array(2, 3, 5, 1, 6, 4)
def inject(arr: Array[Int], initial: Int)(operation: (Int, Int) => Int): Int = { // similar with `foldLeft`
var carryOver = initial
for (element <- array) carryOver = operation(carryOver, element)
carryOver
}
val sum = inject(array, 0)((sum, elem) => sum + elem) // array.sum
val max = inject(array, Integer.MIN_VALUE) { (large, elem) => Math.max(large, elem) } // array.max
// Parameter routing (simplify)
val largest1 = (Integer.MAX_VALUE /: array) { (carry, elem) => Math.max(carry, elem) }
val largest2 = (Integer.MAX_VALUE /: array) { Math.max(_, _) }
val largest3 = (Integer.MAX_VALUE /: array) { Math.max _ } // '_' represents list of arguments
val largest4 = (Integer.MAX_VALUE /: array) { Math.max }
// Partial function
def log(date: java.util.Date, message: String): Unit = {
println(s"$date --- $message")
}
val dateToday = new java.util.Date()
val logWithData = log(dateToday, _: String) // logWithData: String => Unit
logWithData("some message")
// Pass code block and wrap around
class Resource private {
println("starting")
def doSomething(): Unit = { println("do something") }
private def cleanUp(): Unit = { println("ending") }
}
object Resource {
def use(codeBlock: Resource => Unit): Unit = {
val resource = new Resource
try {
codeBlock(resource)
} finally {
resource.cleanUp()
}
}
}
Resource.use(resource => { // Execute Around Method design pattern
resource.doSomething()
})
// Trait (class)
trait Friend {
val name: String // no actual value, so it's abstract
def listen(): Unit = println(s"Your friend $name is listening")
}
class Human(val name: String) extends Friend
class Man(override val name: String) extends Human(name)
abstract class Animal
class Dog(val name: String) extends Animal with Friend
new Man("jason").listen()
new Dog("husky").listen()
// Mix-in trait into an instance
class Cat(val name: String) extends Animal
val angel = new Cat("Angel") with Friend
angel.listen()
// Set and Map
val mySet = Set("foo", "bar")
val myMap = Map("foo" -> 1, "bar" -> 2)
myMap.get("foo") // got Option[Int]
myMap("foo") // may throw NoSuchElementException
// Methods end with some special characters will be bind to the second variable (':', '+', '-', '!', '~')
class Sample {
def unary_!(): Unit = println("called unary '!'")
}
val sample = new Sample
!sample
// List
val listExample = List("foo", "bar")
"hello" :: listExample // prepend
List("hello", "world") ::: listExample // prepend
// For expression
for (_ <- 1 to 3) print("ho ")
for (i <- 1 to 9; j <- i to 9) println(s"$i * $j = ${i * j}")
// For ... yield (generator)
val doubles = for (i <- 1 to 9) yield i * 2
val doubles2 = for (i <- 1 to 9; result = i * 2) yield result
val doubleEvens = for (i <- 1 to 9; if i % 2 == 0) yield i * 2
val doubleEvens2 = for (i <- 1 to 9; result = i * 2; if i % 2 == 0) yield result
// Pattern match: constants
var input: Any
input match {
case "day" => println("matched day")
case DayOfWeek.FRIDAY => println("matched Friday")
case _ => println("not matched")
}
// Pattern match: lists and tuples
input match {
case ("hello", name) => println(s"hello $name")
case (foo, bar) => println(s"tuple $foo $bar")
}
input match {
case List("apple") => println("apple only")
case List("red", "blue", _*) => println(s"colors red, blue, ...")
}
// Pattern match: type
input match {
case x: Int => print(s"got int $x")
case s: String => printf(s"got string $s")
case (v1: Int, v2: Int) => print(s"got pair of int $v1 $v2")
}
// Pattern match with defence
input match {
case x: Int if x > 1000 => print(s"got big int $x")
case x: Int => print(s"got int $x")
}
// Pattern match: case classes
trait Trade
case class Buy(stock: String, quantity: Int) extends Trade
case class Sell(stock: String, quantity: Int) extends Trade
var trade: Trade
trade match {
case Buy(stock, quantity) => print(s"Buying $quantity units of $stock") // unapply() is called
case Sell(stock, quantity) => print(s"Selling $quantity units of $stock")
}
// Exception handling (try-catch)
try {
Integer.parseInt("12.34")
} catch {
case e: NumberFormatException => print(s"number format error: ${e.getMessage}")
case _: Throwable => print("something went wrong")
}
// Tail recursion (TCO)
@scala.annotation.tailrec // ensure TCO
def factorial(fact: BigInt, number: Int): BigInt = {
if (number == 0) fact
else factorial(fact * number, number - 1)
}
println(factorial(1, 1000))
// Lazy value
lazy val lazyValue = System.currentTimeMillis
// Non-strict (lazy) view of strict collections (like `stream()` in Java)
val people = List(("Mark", 32), ("Bob", 22), ("Jane", 8), ("Jill", 21), ("Nick", 50), ("Nancy", 42))
people.filter(_._2 > 17).filter(_._1.startsWith("J")).head
people.view.filter(_._2 > 17).filter(_._1.startsWith("J")).head // compute lazily
// Stream
def generate(starting: Int = 0): Stream[Int] = starting #:: generate(starting + 1) // "#::" means concat lazily
println(generate()) // got Stream(0, ?)
println(generate().take(10).force) // got Stream(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
println(generate().take(10).toList) // got List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
// Parallel collections
def squareSlow(input: Int): Int = {
println(s"computing square for $input ...")
Thread.sleep(1000)
input * input
}
val inputs = List(1, 2, 3, 4, 5)
inputs.map(squareSlow) // cost 5 secs
inputs.par.map(squareSlow) // cost 1 secs
// Input from console
import scala.io.StdIn
val symbol = StdIn.readLine()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment